LINQ to Entities no reconoce el método

116

Recibo el siguiente error al intentar hacer una consulta de linq:

LINQ to Entities no reconoce el método 'Boolean IsCharityMatching (System.String, System.String)', y este método no se puede traducir a una expresión de tienda.

He leído muchas preguntas anteriores en las que las personas obtienen el mismo error, y si lo entiendo correctamente es porque LINQ to Entities requiere que toda la expresión de consulta linq se traduzca a una consulta del servidor y, por lo tanto, no puede llamar a un método externo en eso. Todavía no he podido convertir mi escenario en algo que funcione, y mi cerebro está comenzando a derretirse, por lo que esperaba que alguien pudiera señalarme en la dirección correcta. Estamos usando Entity Framework y el patrón de especificación (y soy nuevo en ambos).

Aquí está el código que usa la especificación:

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

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

Aquí está la expresión linq:

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

Aquí está el 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;
}

Avísame si necesitas más información.

Muchas gracias,

Annelie

annelie
fuente
verifique esta respuesta
Eranga
También comprobaré esto, ¡gracias!
annelie
1
Sería bueno ver cómo lo usa Find()cuando, cómo lo usa IsSatisfied()dentro de él.
Alisson

Respuestas:

124

Como ha descubierto, Entity Framework no puede ejecutar su código C # como parte de su consulta. Tiene que poder convertir la consulta en una declaración SQL real. Para que eso funcione, tendrá que reestructurar su expresión de consulta en una expresión que Entity Framework pueda manejar.

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()));
}
StriplingGuerrero
fuente
1
en caso de duda, búsquelo: stackoverflow.com/questions/2352764/…
Chris Hayes
2
Devolver un construido Expression<Func<T,type>>es un enfoque muy agradable para esto.
Travis J
¿Cómo usarías esto en una expresión LINQ? Me gustaría hacer algo como esto como una cláusula Where reutilizable pero tengo problemas para implementarla.
Zorgarath
4
EDITAR: no importa, sería:context.Where(IsSatisfied())
Zorgarath
Parte clave: "Entity Framework no puede ejecutar su código C # como parte de su consulta"
Alper
1

Recibí el mismo error en este 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 fue exactamente el error:

System.NotSupportedException: 'LINQ to Entities no reconoce el método' Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) ', y este método no se puede traducir a una expresión de tienda.'

Resolví de esta manera:

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

Agregué un .ToList () antes de mi tabla, esto desacopla el código Entity y linq, y evita que mi próxima expresión linq se traduzca

NOTA: esta solución no es óptima, porque evita el filtrado de entidades y simplemente carga toda la tabla en la memoria

En g. Gerardo Sánchez
fuente
1
La mayoría de las veces, esta es la solución más fácil, pero para no cargar todo el objeto, generalmente hago una selección anónima antes de .ToList () con justo lo que necesito ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Select (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("dd / MM / aaaa")})
Diógenes
0

Si alguien está buscando una respuesta de VB.Net (como yo estaba inicialmente), aquí 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
fuente
-1

Tuve un problema similar al tuyo y esta documentación de LINQ me ayudó a encontrar las funciones de cadena adecuadas para solucionar las limitaciones.

Michael Fayad
fuente