2010-03-15 15 views
13

Supongamos que tengo un objeto entidad definida comoReutilizando LINQ to Expresión Entidades <Func <T, TResult> en Seleccionar y donde las llamadas

public partial class Article 
{ 
    public Id 
    { 
     get; 
     set; 
    } 
    public Text 
    { 
     get; 
     set; 
    } 
    public UserId 
    { 
     get; 
     set; 
    } 
} 

Basado en algunas propiedades de un artículo, necesito para determinar si el artículo se puede eliminar por un usuario dado. Entonces agrego un método estático para hacer la verificación. Algo así como:

public partial class Article 
{ 
    public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId) 
    { 
     //Add logic to be reused here 
     return a => a.UserId == userId; 
    } 
} 

Así que ahora puede hacer

using(MyEntities e = new MyEntities()) 
{ 
    //get the current user id 
    int currentUserId = 0; 

    e.Articles.Where(Article.CanBeDeletedBy(currentUserid)); 
} 

Hasta aquí todo bien. Ahora quiero volver a utilizar la lógica en CanBeDeletedBy mientras se hace a Seleccione, algo así como:

using(MyEntities e = new MyEntities()) 
{ 
    //get the current user id 
    int currentUserId = 0; 

    e.Articles.Select(a => new 
    { 
     Text = a.Text, 
     CanBeDeleted = ??? 
    }; 
} 

Pero no importa lo que intente, no puedo usar la expresión en el método de selección. Supongo que si puedo hacer

e.Articles.Select(a => new 
    { 
     Text = a.Text, 
     CanBeDeleted = a => a.UserId == userId 
    }; 

Entonces debería ser capaz de usar la misma expresión. Intentó compilar la expresión y llamarla haciendo

e.Articles.Select(a => new 
    { 
     Text = a.Text, 
     CanBeDeleted = Article.CanBeDeletedBy(currentUserId).Compile()(a) 
    }; 

pero no funcionará tampoco.

¿Alguna idea sobre cómo hacer que esto funcione? O si no es posible, ¿cuáles son las alternativas para reutilizar la lógica comercial en ambos lugares?

Gracias

Pedro

+0

La compilación de la expresión es la elección correcta y compila y funciona para mí. Si fuera yo, también tomaría en cuenta la compilación. Qué error estás recibiendo ? –

+0

Sí, compila bien, pero arroja una excepción NotSupportedException: "LINQ to Entities no admite el tipo de nodo de expresión LINQ 'Invoke'." Intenté compilar la expresión fuera del Seleccionar en un Func y usarlo adentro, con el mismo resultado. – Pedro

+0

Por cierto, si uso un Func , y lo uso en el Donde el método, entonces la consulta se ejecutará en el cliente, que no es el propósito previsto. – Pedro

Respuesta

4

reutilización de los árboles de expresión es un arte negro; puedes hacerlo, pero necesitarías cambiar mucho código para reflejar y perderías toda la comprobación estática. En particular, trabajar con tipos anónimos se convierte en una pesadilla (aunque dynamic en 4.0 podría funcionar).

Además, si haces trampa y usas Expression.Invoke, entonces no es compatible con todos los proveedores (la mayoría notablemente no está en EF en .NET 3.5SP1).

A menos que este sea un punto importante, lo dejaría con duplicación. O ¿necesita para volver a utilizar el árbol de expresiones?

+1

Don ' Realmente necesito volver a usar el árbol de expresiones. Fue solo para tratar de no duplicar el código relacionado con la seguridad. Pero lo haré por ahora, y veré si puedo refactorizar el código más tarde. Gracias – Pedro

3

Lo que hice es Solía ​​PredicateBuilder que es una clase de LinqKit y también AsExpandable() http://www.albahari.com/nutshell/linqkit.aspx para construir expresiones y los guardó como estáticamente

public readonly Expression<Func<T,bool>> 

en una clase estática. Cada expresión se basaba en una expresión previa, reduciendo así la cantidad de duplicaciones.

Como la pregunta anterior de Marc Gravell sugiere que este algo es un arte negro, pero afortunadamente mucho del trabajo ha sido realizado por otra persona.

Cuestiones relacionadas