LINQ to Entities non riconosce il metodo


116

Ricevo il seguente errore quando provo a eseguire una query su linq:

LINQ to Entities non riconosce il metodo "Boolean IsCharityMatching (System.String, System.String)" e questo metodo non può essere tradotto in un'espressione di archivio.

Ho letto molte domande precedenti in cui le persone ottengono lo stesso errore e se lo capisco correttamente è perché LINQ to Entities richiede che l'intera espressione di query linq sia tradotta in una query del server, e quindi non è possibile chiamare un metodo esterno dentro. Non sono ancora riuscito a convertire il mio scenario in qualcosa che funzioni, e il mio cervello sta iniziando a sciogliersi, quindi speravo che qualcuno potesse indicarmi la giusta direzione. Stiamo usando Entity Framework e il modello di specifica (e sono nuovo per entrambi).

Ecco il codice che utilizza la specifica:

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

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

Ecco l'espressione linq:

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

Ecco il metodo 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;
}

Fammi sapere se hai bisogno di ulteriori informazioni.

Grazie molto,

Annelie



Controllerò anche questo, grazie!
annelie

1
Sarebbe bello vedere come lo usi Find()quando come lo usi IsSatisfied()al suo interno.
Alisson

Risposte:


124

Come hai capito, Entity Framework non può effettivamente eseguire il codice C # come parte della sua query. Deve essere in grado di convertire la query in un'effettiva istruzione SQL. Affinché funzioni, dovrai ristrutturare la tua espressione di query in un'espressione che Entity Framework può gestire.

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

1
in caso di dubbio cercalo
Chris Hayes

2
Restituire un costruito Expression<Func<T,type>>è un approccio molto carino a questo.
Travis J

Come lo useresti in un'espressione LINQ? Vorrei fare qualcosa di simile come una clausola Where riutilizzabile, ma sto lottando per implementarla.
Zorgarath

4
EDIT: non importa, sarebbe:context.Where(IsSatisfied())
Zorgarath

Parte fondamentale: "Entity Framework non può effettivamente eseguire il codice C # come parte della sua query."
Alper

1

Ho ricevuto lo stesso errore in questo codice:

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

questo era esattamente l'errore:

System.NotSupportedException: "LINQ to Entities non riconosce il metodo" Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) "e questo metodo non può essere tradotto in un'espressione di negozio."

Ho risolto in questo modo:

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

Ho aggiunto un .ToList () prima della mia tabella, questo disaccoppia il codice Entity e linq ed evita che la mia prossima espressione linq venga tradotta

NOTA: questa soluzione non è ottimale, perché evita il filtraggio delle entità e carica semplicemente tutta la tabella in memoria


1
La maggior parte delle volte questa è la soluzione più semplice, ma per non caricare tutto l'oggetto di solito faccio una selezione anonima prima di .ToList () con proprio ciò di cui ho bisogno ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Seleziona (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("dd / MM / yyyy")})
Diógenes

0

Se qualcuno sta cercando una risposta VB.Net (come ero inizialmente), eccola:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.