Невозможно выполнить рефакторинг с использованием LINQ to Entities и LinqKit/PredicateBuilder.
Вопрос
Я пытался преобразовать выражение LINQ в метод и столкнулся как сInternal .NET Framework Data Provider error 1025.
" и "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.
"исключения.
Вот соответствующие части модели объекта (с использованием EF 4.2/LINQ to Entities):
public class Place : Entity
{
public string OfficialName { get; protected internal set; }
public virtual ICollection<PlaceName> { get; protected internal set; }
}
public class PlaceName : Entity
{
public string Text { get; protected internal set; }
public string AsciiEquivalent { get; protected internal set; }
public virtual Language TranslationTo { get; protected internal set; }
}
public class Language : Entity
{
public string TwoLetterIsoCode { get; protected internal set; }
}
Базовая реляционная модель такова:
Place (1) <-----> (0..*) PlaceName (0..*) <-----> (0..1) Language
Я пытаюсь создать запрос, который при поиске будет term
, попытаться найти Place
субъекты, чьи OfficialName
начинается с term
ИЛИ у кого есть PlaceName
чей Text
или AsciiEquivalent
начинается с поиска term
. (Language
У меня проблемы не с этим, хотя это часть запроса, потому что PlaceName
s должно соответствовать только CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName
.)
Следующий код работает:
internal static IQueryable<Place> WithName(this IQueryable<Place> queryable,
string term)
{
var matchesName = OfficialNameMatches(term)
.Or(NonOfficialNameMatches(term));
return queryable.AsExpandable().Where(matchesName);
}
private static Expression<Func<Place, bool>> OfficialNameMatches(string term)
{
return place => place.OfficialName.StartsWith(term);
}
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
return place => place.Names.Any(
name =>
name.TranslationToLanguage != null
&&
name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
&&
(
name.Text.StartsWith(term)
||
(
name.AsciiEquivalent != null
&&
name.AsciiEquivalent.StartsWith(term)
)
)
);
}
Дальше я пытаюсь провести рефакторинг NonOfficialNameMatches
метод извлечения name => ...
выражение в отдельный метод, чтобы его можно было повторно использовать в других запросах.Вот один пример, который я попробовал, который не работает и выдает исключение "The parameter 'place' was not bound in the specified LINQ to Entities query expression.
":
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
return place => place.Names.AsQueryable().AsExpandable()
.Any(PlaceNameMatches(term));
}
public static Expression<Func<PlaceName, bool>> PlaceNameMatches(string term)
{
var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
return name =>
name.TranslationToLanguage != null
&&
name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
&&
(
name.Text.StartsWith(term)
||
(
name.AsciiEquivalent != null
&&
name.AsciiEquivalent.StartsWith(term)
)
);
}
Когда у меня нет .AsExpandable()
цепочка в NonOfficialNameMatches
, то я получаю "Internal .NET Framework Data Provider error 1025.
" исключение.
Я последовал за другой совет здесь например, несколько комбинаций вызова .Expand()
на предикаты, но всегда приводит к одному из вышеупомянутых исключений.
Можно ли вообще выделить это выражение в отдельный метод, используя LINQ to Entities с помощью LinqKit/PredicateBuilder? Если да, то как?Что я делаю не так?
Решение
Метод ниже должен работать:
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
Expression<Func<PlaceName, bool>> placeNameExpr = PlaceNameMatches(term);
Expression<Func<Place, bool>> placeExpr =
place => place.Names.Any(name => placeNameExpr.Invoke(name));
return placeExpr.Expand();
}
РЕДАКТИРОВАТЬ:Добавляем дополнительные пояснения
А PlaceNameMatches
метод работает так, как вы написали.Ваши проблемы заключались в том, как вы использовали этот метод.Если вы хотите выделить части выражения, выполните три шага, которые я выполнил в методе выше.
Установите локальную переменную в выражение, созданное методом.
Установите другую локальную переменную в новое выражение, которое вызывает выражение локальной переменной.
Вызов LinkKit
Expand
метод:это расширит любые вызванные выражения