Search code examples
c#linqef-core-3.1

Argument type IOrderedQueryable does not match the corresponding member type IOrderedEnumerable (LINQ to SQL)


I'm trying to run this LINQ-to-SQL query

var sourceFilters = await _context.Sources.Where(s => s.CreatedBy == userId).Select(s => new  {
            SourceId = s.Id,
            SourceName = s.Name,
            Models = s.Vehicles.Select(v => new VehicleKeys()
                        {
                            Model = v.Model,
                            Code = v.Code,
                            RegistrationNumber = v.RegistrationNumber
                        }).Distinct().OrderBy(k => k.Model).ThenBy(k => k.Code).ThenBy(k => k.RegistrationNumber)
        }).ToListAsync()

s.Vehicles is a navigation property

But I get the following Exception:

Argument type 'System.Linq.IOrderedQueryable`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]' does not match the corresponding member type 'System.Linq.IOrderedEnumerable`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]'

I tried adding .ToList() after all of the OrderBy calls, but then the resulting sourceFilters.Models collection only has a single element (even if I add Include(s=>s.Vehicles) to _context.Sources)

I also tried turning anonymous type into a normal type SourceKeys, but if I define Models property as a IOrderedQueryable or IQueryable - I get a compile time error. If I define it as a IEnumerable or IOrderedEnumerable - I get an Argument types do not match exception

Another thing I attempted was adding AsQueryable(), right after s.Vehicles, after Distinct() or after all of the OrderBy clauses. In the first and second cases I get the following exception:

Argument type 'System.Linq.IQueryable`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]' does not match the corresponding member type 'System.Linq.IOrderedQueryable`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]'

In the third case I get:

Argument type 'System.Collections.Generic.List`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]' does not match the corresponding member type 'System.Linq.IQueryable`1[MyProject.Infrastructure.Services.SourceService+VehicleKeys]'

I've also tried both having a named type for the elements of the sourceFilters collection, and adding AsQueryable()

If I have Models be IOrderedQueryable<VehicleKeys> and put AsQueryable() after s.Vehicles or after Distinct() I get the Argument types do not match exception. If I put AsQueryable() after all of the OrderBy() clauses - I get a compile error.

If I have Models be IQueryable<VehicleKeys> I get Argument types do not match exception, no matter where I put AsQueryable().

At this point I have absolutely no ideas on what else to try. I can work around the problem by doing the ordering on the client-side, but I would prefer to things like ordering on the SQL Server, to leverage the benefits of indexation, and I also really want to understand what's the cause of the problem, so if similar problems were to pop up in the future I would be able to deal with them.

Edit: Models:

public class Source {
    public int Id { get; set; }
    public string Name { get; set; }
    public string CreatedBy { get; set; }
    public virtual IEnumerable<Vehicle> Vehicles { get; set; }
}

public class Vehicle {
    public int Id { get; set; }
    public string Model { get; set; }
    public string Code { get; set; }
    public string RegistrationNumber { get; set; }
    public int? SourceId { get; set; }
    public Source Source { get; set; }
    //some other properties
}

{Model, Code, RegistrationNumber, SourceId, /* some other properties*/} have an index and an unique constraint

private class VehicleKeys {
    public string Model { get; set; }
    public string Code { get; set; }
    public string RegistrationNumber { get; set; }
}

Solution

  • I would suggest to split this query to two parts. One should execute Eager Loading query, second post process records on the client side:

    var rawData = await _context.Sources
        .Where(s => s.CreatedBy == userId)
        .Select(s => new  
        {
            SourceId = s.Id,
            SourceName = s.Name,
            Models = s.Vehicles
                .Select(v => new 
                {
                    Model = v.Model,
                    Code = v.Code,
                    RegistrationNumber = v.RegistrationNumber
                }).ToList()
        })
        .ToListAsync();
    
    var sourceFilters = rawData
        .Select(s => new  
        {
            s.SourceId,
            s.SourceName,
            Models = s.Models
                .Distinct()
                .OrderBy(k => k.Model)
                .ThenBy(k => k.Code)
                .ThenBy(k => k.RegistrationNumber)
                .Select(v => new VehicleKeys()
                {
                    Model = v.Model,
                    Code = v.Code,
                    RegistrationNumber = v.RegistrationNumber
                }).ToList()
        })
        .ToList();