LINQ to Entities não reconhece o método

116

Estou recebendo o seguinte erro ao tentar fazer uma consulta linq:

LINQ to Entities não reconhece o método 'Boolean IsCharityMatching (System.String, System.String)' e esse método não pode ser convertido em uma expressão de armazenamento.

Eu li muitas perguntas anteriores em que as pessoas obtêm o mesmo erro e, se entendi corretamente, é porque o LINQ to Entities requer que toda a expressão de consulta do linq seja traduzida para uma consulta de servidor e, portanto, você não pode chamar um método externo iniciar. Ainda não consegui converter meu cenário em algo que funcione, e meu cérebro está começando a derreter, então esperava que alguém pudesse me apontar a direção certa. Estamos usando o Entity Framework e o padrão de especificação (e sou novo em ambos).

Este é o código que usa a especificação:

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

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

Aqui está a expressão linq:

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

Este é o método 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;
}

Deixe-me saber se você precisar de mais informações.

Muito Obrigado,

Annelie

Annelie
fonte
verifique esta resposta
Eranga
Vou verificar isso também, obrigado!
Annelie
1
Seria bom ver como você está usando e Find()quando usa IsSatisfied()dentro dele.
Alisson,

Respostas:

124

Como você descobriu, o Entity Framework não pode realmente executar seu código C # como parte de sua consulta. Ele deve ser capaz de converter a consulta em uma instrução SQL real. Para que isso funcione, você terá que reestruturar sua expressão de consulta em uma expressão que o Entity Framework possa manipular.

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
fonte
1
em caso de dúvida, pesquise: stackoverflow.com/questions/2352764/…
Chris Hayes
2
Retornar um construído Expression<Func<T,type>>é uma abordagem muito boa para isso.
Travis J
Como você usaria isso em uma expressão LINQ? Eu gostaria de fazer algo como isso como uma cláusula Where reutilizável, mas estou lutando para implementá-la.
Zorgarath
4
EDIT: esquece, seria:context.Where(IsSatisfied())
Zorgarath
Parte-chave: "Entity Framework não pode realmente executar seu código C # como parte de sua consulta."
Alper
1

Recebi o mesmo erro neste código:

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

este foi exatamente o erro:

System.NotSupportedException: 'LINQ to Entities não reconhece o método' Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) ', e este método não pode ser traduzido em uma expressão de armazenamento.'

Eu resolvi assim:

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();

Eu adicionei um .ToList () antes da minha tabela, isso desacopla a Entidade e o código linq e evito que minha próxima expressão linq seja traduzida

NOTA: esta solução não é a ideal, porque evita a filtragem de entidades e simplesmente carrega todas as tabelas na memória

Ing. Gerardo Sánchez
fonte
1
Na maioria das vezes, essa é a solução mais fácil, mas para não carregar todos os objetos, geralmente faço uma seleção anônima antes de .ToList () com apenas o que preciso ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Select (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("dd / MM / aaaa")})
Diógenes
0

Se alguém está procurando uma resposta VB.Net (como eu estava inicialmente), aqui está:

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
fonte
-1

Tive um problema semelhante ao seu e esta documentação do LINQ me ajudou a encontrar as funções de string certas para contornar as limitações.

Michael Fayad
fonte