Reputation: 168
In .NET Core 2.X, I was able to use this code below:
var bookings = await db.Tasks
.Where(c => c.ClientId == clientId && c.IsDeleted == false && c.Start > startOfThisMonth && c.End < endOfThisMonth)
.OrderBy(x => x.Start)
.Select(x => new SpecialTaskVm(new TaskViewModel(x, null))
{
client = x.Client,
carer = x.Booking.SingleOrDefault(b => b.SlotNumber == 1).Carer,
carer2 = x.Booking.SingleOrDefault(bk => bk.SlotNumber == 2).Carer
})
.ToListAsync();
However the same code in .net core 3.X results in this error:
System.InvalidOperationException: When called from 'VisitMemberInit', rewriting a node of type 'System.Linq.Expressions.NewExpression' must return a non-null value of the same type. Alternatively, override 'VisitMemberInit' and change it to not visit children of this type.
I could really do with selecting in the way I do above as each model does some modification to some properties and each model is used elsewhere separately.
I am also trying to avoid a foreach
as it seems that would be inefficient.
I have tried passing the properties I need to set, into the model and setting them in the model like that. Same error occurs.
//This action method will return data for current month.
var startOfThisMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
var endOfThisMonth = new DateTime(DateTime.Now.Year, DateTime.Now.AddMonths(1).Month, 1);
var bookings = await db.Tasks
.Where(c => c.ClientId == clientId && c.IsDeleted == false && c.Start > startOfThisMonth && c.End < endOfThisMonth)
.OrderBy(x => x.Start)
.Select(x => new SpecialTaskVm(new TaskViewModel(x, null))
{
client = x.Client,
carer = x.Booking.SingleOrDefault(b => b.SlotNumber == 1).Carer,
carer2 = x.Booking.SingleOrDefault(bk => bk.SlotNumber == 2).Carer
})
.ToListAsync();
I expect for the list of tasks to be returned in the form of List<SpecialTaskVm>
with Client
, Carer
and Carer2
set.
Upvotes: 2
Views: 4850
Reputation: 118937
It's a bit unusual to use a constructor and object initialisation syntax in the same code, to me that's already a code smell.
If I were you, I would create an intermediate list that only gets values from the database, then project that data into your SpecialTaskVm
objects. For example:
// First get the data from the database in a simple form we can parse through later
var bookingData = await db.Tasks
.Where(c => c.ClientId == clientId && c.IsDeleted == false && c.Start > startOfThisMonth && c.End < endOfThisMonth)
.OrderBy(x => x.Start)
.Select(x => new // Use an anonymous type
{
Client = x.Client,
Carer = x.Booking.SingleOrDefault(b => b.SlotNumber == 1).Carer,
Carer2 = x.Booking.SingleOrDefault(bk => bk.SlotNumber == 2).Carer
})
.ToListAsync();
// Now we massage the data into a format we can use
var bookings = bookingData
.Select(x => new SpecialTaskVm(new TaskViewModel(x, null))
{
client = x.Client,
carer = x.Carer,
carer2 = x.Carer2
})
.ToList();
Additionally, I would potentially recommend changing the SpecialTaskVm
constructor (or add a new one) to include the new fields.
Upvotes: 3