LINQ to Entities не распознает метод

116

При попытке выполнить запрос linq появляется следующая ошибка:

LINQ to Entities не распознает метод Boolean IsCharityMatching (System.String, System.String), и этот метод нельзя преобразовать в выражение хранилища.

Я читал много предыдущих вопросов, где люди получают ту же ошибку, и если я правильно это понимаю, это потому, что LINQ to Entities требует, чтобы все выражение запроса linq было преобразовано в запрос сервера, и поэтому вы не можете вызвать внешний метод в этом. Мне еще не удалось превратить свой сценарий во что-то, что работает, и мой мозг начинает таять, поэтому я надеялся, что кто-то может указать мне правильное направление. Мы используем Entity Framework и шаблон спецификации (и я новичок в обоих).

Вот код, который использует спецификацию:

ISpecification<Charity> specification = new CharitySearchSpecification(charityTitle, charityReference);

charities = charitiesRepository.Find(specification).OrderBy(p => p.RegisteredName).ToList();

Вот выражение linq:

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    return p => p.IsCharityMatching(this.charityName, this.charityReference);
}

Вот метод IsCharityMatching:

public bool IsCharityMatching(string name, string referenceNumber)
{
    bool exists = true;

    if (!String.IsNullOrEmpty(name))
    {
        if (!this.registeredName.ToLower().Contains(name.ToLower()) &&
            !this.alias.ToLower().Contains(name.ToLower()) &&
           !this.charityId.ToLower().Contains(name.ToLower()))
        {
            exists = false;
        }
    }

    if (!String.IsNullOrEmpty(referenceNumber))
    {
        if (!this.charityReference.ToLower().Contains(referenceNumber.ToLower()))
        {
            exists = false;
        }
    }

    return exists;
}

Дайте мне знать, если вам понадобится дополнительная информация.

Большое спасибо,

Аннели

Аннели
источник
проверьте этот ответ
Eranga
Это тоже проверю, спасибо!
Annelie
1
Было бы неплохо увидеть, как вы используете, Find()когда используете IsSatisfied()внутри него.
Alisson

Ответы:

124

Как вы уже выяснили, Entity Framework не может выполнять ваш код C # как часть своего запроса. Он должен иметь возможность преобразовывать запрос в фактический оператор SQL. Чтобы это сработало, вам нужно будет преобразовать выражение запроса в выражение, которое может обрабатывать Entity Framework.

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    string name = this.charityName;
    string referenceNumber = this.referenceNumber;
    return p => 
        (string.IsNullOrEmpty(name) || 
            p.registeredName.ToLower().Contains(name.ToLower()) ||
            p.alias.ToLower().Contains(name.ToLower()) ||
            p.charityId.ToLower().Contains(name.ToLower())) &&
        (string.IsNullOrEmpty(referenceNumber) ||
            p.charityReference.ToLower().Contains(referenceNumber.ToLower()));
}
StriplingWarrior
источник
1
если сомневаетесь, найдите это: stackoverflow.com/questions/2352764/…
Крис Хейс,
2
Возврат сконструированного Expression<Func<T,type>>- очень хороший подход к этому.
Travis J
Как бы вы использовали это в выражении LINQ? Я хотел бы сделать что-то подобное как предложение Where, которое можно использовать повторно, но мне трудно его реализовать.
Зоргарат
4
РЕДАКТИРОВАТЬ: неважно, это будет:context.Where(IsSatisfied())
Зоргарат
Ключевая часть: «Entity Framework не может фактически запускать ваш код C # как часть своего запроса»
Альпер,
1

У меня такая же ошибка в этом коде:

 var articulos_en_almacen = xx.IV00102.Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

это была именно ошибка:

System.NotSupportedException: 'LINQ to Entities не распознает метод' Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) ', и этот метод нельзя преобразовать в выражение хранилища.'

Я решил так:

var articulos_en_almacen = xx.IV00102.ToList().Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

Я добавил .ToList () перед своей таблицей, это отделяет код Entity и linq и позволяет избежать перевода следующего выражения linq

ПРИМЕЧАНИЕ: это решение не оптимально, потому что избегает фильтрации сущностей и просто загружает всю таблицу в память.

Ing. Херардо Санчес
источник
1
В большинстве случаев это самое простое решение, но чтобы не загружать весь объект, я обычно делаю анонимный выбор перед .ToList () с тем, что мне нужно ... xx.Select (x => new {x.Id, x.DateTimeUpdate }) ToList () Выбрать (х => новый {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ( "дд / мм / гггг".)}).
Diógenes
0

Если кто-то ищет ответ VB.Net (как и я изначально), вот он:

Public Function IsSatisfied() As Expression(Of Func(Of Charity, String, String, Boolean))

Return Function(charity, name, referenceNumber) (String.IsNullOrWhiteSpace(name) Or
                                                         charity.registeredName.ToLower().Contains(name.ToLower()) Or
                                                         charity.alias.ToLower().Contains(name.ToLower()) Or
                                                         charity.charityId.ToLower().Contains(name.ToLower())) And
                                                    (String.IsNullOrEmpty(referenceNumber) Or
                                                     charity.charityReference.ToLower().Contains(referenceNumber.ToLower()))
End Function
Mik
источник
-1

У меня была проблема, похожая на вашу, и эта документация LINQ помогла мне найти правильные строковые функции для обхода ограничений.

Майкл Файад
источник