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; }
}
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();