Im am trying to build a nested DTO with Entity Framework (6.2.0) using navigation properties. The navigation properties are optional, so I need to handle null values in a way that the corresponding property of the DTO is null also:
var result = db.Projects.Select(
p => new
{
p.Id,
Notifications = p.Notifications
.Where(n => n.ContactId == user.Id)
.Select(a => new
{
a.Id,
a.ContactId,
Candidate = a.Candidate == null ? null : new
{
a.Candidate.Id,
a.Candidate.LastName
}
})
.OrderByDescending(n => n.Timestamp)
})
.FirstOrDefault(p => p.Id == projectId);
As the code shows, in my model, there are Project
entities with 0-n Notifications
, where a Notification
can optionally have one Candidate
.
The above code throws:
System.InvalidOperationException: 'No coercion operator is defined
between types 'System.Linq.Expressions.Expression[]' and
'<>f__AnonymousType43`2[System.Int32,System.String]'.'
at runtime. If I remove the null check like so
Candidate = new
{
a.Candidate.Id,
a.Candidate.LastName
}
it expectedly throws an exception when the Candidate
property is null. Null propagation does not work either, and - even if it did - would not meet the requirement that the DTO property Candidate
should be null and not an object with null property values:
Candidate = new
{
Id = a.Candidate?.Id,
LastName = a.Candidate?.LastName
}
This does not compile:
An expression tree lambda may not contain a null propagating operator.
- How can I create a nested DTO with optional properties based on (optional) navigation properties?
- What is considered best practice for this (not so exotic?) requirement?
For reference, the definition of the navigation properties:
modelBuilder.Entity<Project>(entity =>
{
// ...
entity.HasMany(p => p.Notifications)
.WithOne(a => a.Project)
.HasForeignKey(a => a.ProjectId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<Notification>(entity =>
{
// ...
entity.HasOne(e => e.Candidate)
.WithMany(c => c.Notifications)
.HasForeignKey(e => e.CandidateId)
.HasPrincipalKey(e => e.Guid)
.IsRequired(false)
.OnDelete(DeleteBehavior.SetNull);
});
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…