0

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.

u05sdb
  • 35
  • 5

0 Answers0