将Linq重用于实体的表达式<func <t,tresult =“”>在Select和Where调用中</func <t,>

时间:2010-03-15 11:44:10

标签: 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 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.Where(Article.CanBeDeletedBy(currentUserid));  
}

到目前为止一切顺利。现在我想在执行Select时重用CanBeDeletedBy中的逻辑,例如:

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

但它也不起作用。

有关如何使其发挥作用的任何想法?或者,如果不可能,在两个地方重用业务逻辑的替代方案是什么?

由于

佩德罗

2 个答案:

答案 0 :(得分:4)

重复使用表达式树是一种黑色艺术;你可以做到,但你需要将大量代码切换到反射,你将失去所有的静态检查。特别是,使用匿名类型变成了一场噩梦(虽然4.0中的dynamic可能是可行的。)

此外,如果你作弊并使用Expression.Invoke,那么所有提供商都不支持它(最明显的是不支持.NET 3.5SP1中的EF)。

除非这是一个主要的痛点,否则我会留下重复。或者你需要来重用表达式树吗?

答案 1 :(得分:3)

我做的是我使用了PredicateBuilder,它是LinqKit中的一个类,也是AsExpandable()http://www.albahari.com/nutshell/linqkit.aspx来构建表达式,我将它们静态存储为

public readonly Expression<Func<T,bool>>

在静态类中。每个表达式都建立在先前的表达式上,从而减少了重复的数量。

正如马克·格拉维尔(Marc Gravell)之前的问题所暗示的那样,这件事是黑色艺术,但值得庆幸的是,其他一些人已经完成了很多工作。