I am using Linq.Dynamic.Core to dynamically create queries for EF Core and I got stuck in the join operation with multiple primary keys. With single primary key tables everything works perfectly.
As a first step, I created an example query in standard Linq:
var resultLinq = ctx.Set<Destination>()
.Join(ctx.Set<DestinationCollectionInfo>(),
p => new { A1 = p.Id, A2 = p.DestinationId },
j => new { A1 = j.Id, A2 = j.DestinationId },
(p, j) => new { Description = p.Description, Collection_Descr = j.Description })
.ToList();
And then I translated it into Dynamic Linq Core as a model:
var resultDynamicLinq = ctx.Set<Destination>()
.Join(ctx.Set<DestinationCollectionInfo>(),
"new { it.Id AS A1, it.DestinationId AS A2 }",
"new { Id AS A1, DestinationId AS A2}",
"new { outer.Description AS Description, inner.Description AS Collection_Descr}")
.ToDynamicList();
Linq query works, instead Dynamic Linq query returns this exception:
System.InvalidOperationException: The LINQ expression 'DbSet<Destination>
.Join(
outer: DbSet<DestinationCollectionInfo>,
inner: d => new <>f__AnonymousType2<int, int>{
A1 = d.Id,
A2 = d.DestinationId
}
,
outerKeySelector: d0 => new <>f__AnonymousType2<int, int>{
A1 = d0.Id,
A2 = d0.DestinationId
}
,
innerKeySelector: (d, d0) => new TransparentIdentifier<Destination, DestinationCollectionInfo>(
Outer = d,
Inner = d0
))' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
Am I doing something wrong or are there limitations in Dynamic Linq? Thank you!
You are doing nothing wrong. But looks like EF Core has some specific query expression requirements which are different from "defaults", so you should use the Dynamic LINQ method overloads having ParsingConfig config
argument and pass ParsingConfig.DefaultEFCore21
, e.g.
.Join(ParsingConfig.DefaultEFCore21, ctx.Set<DestinationCollectionInfo>(),
The overloads without config
simply pass ParsingConfig.Default
. Ideally ParsingConfig.Default
property would have been settable, so one can set it once to ParsingConfig.DefaultEFCore21
and then use the regular overloads. But unfortunately it is read only, so as mentioned at the beginning you have to pass that argument explicitly.