I am trying to make a join and then filter the results:
var result = context.Test1
.Join(context.Test2, q => q.Test11, q => q.Test21, (q, p) => new Tuple<Test1, Test2>(q, p))
.Where(q => q.Item1.Test2 == "test")
.ToList();
The above query is throwing an exception:
The LINQ expression 'DbSet<Test1>()
.Join(
inner: DbSet<Test2>(),
outerKeySelector: t => t.Test11,
innerKeySelector: t0 => t0.Test21,
resultSelector: (t, t0) => new TransparentIdentifier<Test1, Test2>(
Outer = t,
Inner = t0
))
.Where(ti => new Tuple<Test1, Test2>(
ti.Outer,
ti.Inner
).Item1.Test2 == "test")' could not be translated
The problem is here: new Tuple<Test1, Test2>(ti.Outer, ti.Inner).Item1.Test2 == "test")
. When I use an anonymous type for join it works well:
var result = context.Test1
.Join(context.Test2, q => q.Test11, q => q.Test21, (q, p) => new { q, p })
.Where(q => q.q.Test2 == "test")
.ToList();
But the issue is that I am building the query dynamically (using PredicateBuilder) and thus I need a concrete type to be able to build the query. So I am using a method like:
private static Expression<Func<Tuple<Test1, Test2>, bool>> GetTransactionsSearchPredicate(string[] values)
{
var searchPredicate = PredicateBuilder.False<Tuple<Test1, Test2>>();
foreach (var val in values)
{
searchPredicate = searchPredicate.Or(q => q.Item1.Test2 == val);
}
return searchPredicate;
}
I also tried to change Tuple
to a custom type but the error is the same.
Is there anything I could do to make this work? It used to work with EF Core 2 but I think it was just executed locally…
System.Tuple
support is constantly changing/breaking between EF Core versions, so its usage is unreliable.
For EFC 5.0.10 (latest official at this time), it does not work, but custom generic type with settable properties (instead of immutable type with constructor as System.Tuple
) does. e.g. if you replace Tuple
with let say Pair
having the following signature:
public class Pair<T1, T2>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
}
and of course change the constructor call with the more verbose
.Join(context.Test2, q => q.Test11, q => q.Test21,
(q, p) => new Pair<Test1, Test2> { Item1 = q, Item2 = p }) // <--