C# 将Linq重用到实体';表达式<;Func<;T、 TResult>;在Select和Where调用中

C# 将Linq重用到实体';表达式<;Func<;T、 TResult>;在Select和Where调用中,c#,linq,delegates,lambda,C#,Linq,Delegates,Lambda,假设我有一个实体对象定义为 public partial class Article { public Id { get; set; } public Text { get; set; } public UserId { get; set; } } 根据文章的某些属性,我需要确定给定用户是否可以删除该文章。因

假设我有一个实体对象定义为

public partial class Article  
{  
    public Id
    {
        get;
        set;
    }  
    public Text
    {
        get;
        set;
    }  
    public UserId
    {
        get;
        set;
    }  
}
根据文章的某些属性,我需要确定给定用户是否可以删除该文章。因此,我添加了一个静态方法来进行检查。比如:

public partial class Article  
{  
    public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
    {  
        //Add logic to be reused here
        return a => a.UserId == userId;
    }  
}
using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = ???  
    };  
}
到目前为止还不错。现在我想在执行Select时重用CanBeDeletedBy中的逻辑,例如:

public partial class Article  
{  
    public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
    {  
        //Add logic to be reused here
        return a => a.UserId == userId;
    }  
}
using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = ???  
    };  
}
但是无论我尝试什么,我都不能在select方法中使用表达式。我想如果我能做到的话

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = a => a.UserId == userId
    };  
那么我应该可以使用相同的表达式。尝试编译表达式并通过执行以下操作调用它

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = Article.CanBeDeletedBy(currentUserId).Compile()(a)
    }; 
但这也行不通

你有什么办法让它发挥作用吗?或者如果不可能,在这两个地方重用业务逻辑的替代方案是什么

谢谢


佩德罗

重复使用表达式树是一门黑色艺术;您可以这样做,但是您需要将大量代码切换到反射,这样您将丢失所有的静态检查。特别是,使用匿名类型成为一场噩梦(尽管4.0中的
dynamic
可能是可行的)

此外,如果您作弊并使用
Expression.Invoke
,则并非所有提供程序都支持它(最明显的是,并非在.NET3.5SP1中的EF上)


除非这是一个主要的痛点,否则我会让它重复。或者您需要重新使用表达式树吗?

我所做的是使用PredicateBuilder,它是LinqKit中的一个类,也是一个expandable()来构建表达式,并将它们静态存储为

public readonly Expression<Func<T,bool>>
公共只读表达式
在静态类中。每个表达式都是在前一个表达式的基础上构建的,因此减少了重复的数量


正如马克·格雷威尔(Marc Gravell)提出的上一个问题所指出的那样,这类事情是一种黑色艺术,但谢天谢地,其他人做了很多工作。

编译表达式是正确的选择,它为我编译并工作。如果是我的话,我也会把汇编工作考虑在内。您遇到了什么错误?是的,它编译得很好,但引发了NotSupportedException异常:“LINQ to Entities中不支持LINQ表达式节点类型'Invoke'。尝试将Select外部的表达式编译成Func并在内部使用,结果相同。顺便说一句,如果我使用普通Func,并在Where方法中使用它,然后查询将在客户机上执行,这不是预期的目的。啊,对不起,我的错误-错过了使用EF的事实-它可以与linq to对象一起工作:)不需要重新使用表达式树。这只是为了避免重复与安全相关的代码。但我现在会做,看看以后是否可以重构代码。谢谢