I have had difficulties translating linq recently. The latest concerns two queries, both of which execute okay on their own, but not when coupled together through a join.
I have a Case
object and a Car
object such that a Car can have multiple Cases: the Case object has a CarId
property.
I'm trying to join them together, in order to populate my OutputModel, but I also want to retrieve only the most recent case for each car, which I'm trying to achieve with a GroupBy:
private IQueryable<Car> AllActive()
=> _context.Cars.Where(p => p.DeletedAt == null);
private IQueryable<Case> AllActiveCases()
=> _context.Cases.Where(c => c.DeletedAt == null);
var result = await AllActiveCars().Join(
AllActiveCases().GroupBy(c => c.CarId)
.Select(cases => cases.OrderByDescending(c => c.CreatedAt).First()),
x => x.Id, y => y.CarId,
(query1, query2) => new OutputModel
{
CarId = query1.Id,
CaseId = query2.Id
})
.AsNoTracking()
.ToListAsync(cancellationToken);
Which gives
System.InvalidOperationException: 'The LINQ expression 'DbSet<Car>()
.Where(p => p.DeletedAt == null)
.Join(
inner: DbSet<Case>()
.Where(c => c.DeletedAt == null)
.GroupBy(c => c.CarId)
.Select(g => g
.AsQueryable()
.OrderByDescending(e => e.CreatedAt)
.Select(e => IncludeExpression(
EntityExpression:
IncludeExpression(
EntityExpression:
IncludeExpression(
EntityExpression:
e,
NavigationExpression:
EF.Property<Price>(e, "Price"), Price)
,
NavigationExpression:
EF.Property<Price>(e, "Valuation"), Valuation)
,
NavigationExpression:
MaterializeCollectionNavigation(
Navigation: Case.Sellers,
subquery: EF.Property<IReadOnlyCollection<Seller>>(e, "Sellers")
.AsQueryable()), Sellers)
)
.First()),
outerKeySelector: p => (object)p.Id,
innerKeySelector: e0 => (object)e0.CarId,
resultSelector: (p, e0) => new TransparentIdentifier<Car, Case>(
Outer = p,
Inner = e0
))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'
The Join works fine without the GroupBy statement and vice versa.
The classes:
public class Case : IAggregateRoot
{
public long Id { get; private set; }
public long CarId { get; private set; }
private readonly List<Seller> _sellers;
public IReadOnlyCollection<Seller> Sellers => _sellers.AsReadOnly();
public Price? Price { get; private set; }
public Price? Valuation { get; private set; }
public DateTime CreatedAt { get; private set; }
}
public class Car : IAggregateRoot
{
public long Id { get; set; }
public int Doors {get; set; }
}
I am using EF Core 7.0.1. I don't think I am using the methods in an unsupported fashion according to https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/supported-and-unsupported-linq-methods-linq-to-entities?redirectedfrom=MSDN
I have tried the DistinctBy
method outlined in a similar question
return await AllActive().Join(
AllActiveCases().DistinctBy(c=>c.Id, c=>c.CreatedAt),
x => x.Id, y => y.CarId,
(query1, query2) => new OutputModel
{
CarId = query1.Id,
CaseId = query2.Id
})
.AsNoTracking()
.ToListAsync(cancellationToken);
but, although it removes the translation error, it returns all cases.