I need to project some POCO entities from EF into their cut down view model representations for passing to a serializer. The entities in this situation are Shipment and Requisition and have a 0..1 relationship. If I don't pass view models then it'll throw a stack overflow exception while trying to serialize the cyclic references between Requisition and Shipment.
return db.ShipmentRequisitions
.Include(c => c.Shipment)
.Select(r => new ViewModels.Requisition
{
ID = r.ID,
...
Shipment = r.Shipment != null ? new ViewModels.Shipment
{
ID = r.Shipment.ID,
...
} : null
}).AsQueryable();
If the Shipment is null, then I get an exception when trying to access r.Shipment.ID. I added a null check as above and now get the following exception.
Unable to create a constant value of type 'Api.ViewModels.Shipment'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
This strikes me as odd, as it was quite happy to create the nested ViewModels.Shipment as part of the select before I added the null check, so it must be something to do with this.
I can see some EF in the call stack so I tried it in a quick test project with just straight objects to try it with pure LINQ.
var user = users.Select(u => new ViewModel.User
{
Id = u.Id,
Profile = u.Profile != null ? new ViewModel.Profile
{
Id = u.Profile.Id
} : null
}).ToList();
To my surprise with worked. I can't quite figure out what this doesn't work in the first code sample.
UPDATE
I've discovered that if as part of a select I do something like:
.Select(r => new ViewModels.Requisition
{
ID = r.ID,
ShipmentDescription = r.Shipment.Description
})
This is effectively flattening the required Shipment properties into a single DTO. Here I would expect to get a NullReferenceExcetion if Shipment is null on any of the records when setting the Description property. It doesn't happen however. LINQ seems to suppress the exception and the ShipmentDescription comes through just as null. It saves me doing an inline is null check on Shipment for each nested property. Unfortunately this doesn't appear to extend to the same sort of thing when creating a nested object where I'm not flattening.