Невозможно выполнить рефакторинг с использованием LINQ to Entities и LinqKit/PredicateBuilder.

StackOverflow https://stackoverflow.com//questions/10689506

Вопрос

Я пытался преобразовать выражение 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 У меня проблемы не с этим, хотя это часть запроса, потому что PlaceNames должно соответствовать только 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 метод работает так, как вы написали.Ваши проблемы заключались в том, как вы использовали этот метод.Если вы хотите выделить части выражения, выполните три шага, которые я выполнил в методе выше.

  1. Установите локальную переменную в выражение, созданное методом.

  2. Установите другую локальную переменную в новое выражение, которое вызывает выражение локальной переменной.

  3. Вызов LinkKit Expand метод:это расширит любые вызванные выражения

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top