#c# #entity-framework-core #linq-to-sql
Вопрос:
Я пытаюсь присоединиться, а затем отфильтровать результаты:
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 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
Проблема заключается в следующем: new Tuple<Test1, Test2>(ti.Outer, ti.Inner).Item1.Test2 == "test")
. Когда я использую анонимный тип для соединения, он хорошо работает:
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();
Но проблема в том, что я строю запрос динамически (с помощью PredicateBuilder), и поэтому мне нужен конкретный тип, чтобы иметь возможность создавать запрос. Поэтому я использую такой метод, как:
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;
}
Я также попытался перейти Tuple
на пользовательский тип, но ошибка та же.
Могу ли я что-нибудь сделать, чтобы это сработало? Раньше он работал с EF Core 2, но я думаю, что он был просто выполнен локально…
Ответ №1:
System.Tuple
поддержка постоянно меняется/прерывается между версиями ядра EF, поэтому ее использование ненадежно.
Для EFC 5.0.10 (последний официальный на данный момент) он не работает, но пользовательский универсальный тип с настраиваемыми свойствами (вместо неизменяемого типа с конструктором as System.Tuple
) работает. например, если вы замените Tuple
, допустим Pair
, следующую подпись:
public class Pair<T1, T2>
{
public T1 Item1 { get; set; }
public T2 Item2 { get; set; }
}
и, конечно, измените вызов конструктора на более подробный
.Join(context.Test2, q => q.Test11, q => q.Test21,
(q, p) => new Pair<Test1, Test2> { Item1 = q, Item2 = p }) // <--
Комментарии:
1. Это странно, потому что я уже тестировал пользовательский класс, но он не работал. Может быть, это было не публично? В любом случае, работает как заклинание!