Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reusing Linq to Entities' Expression<Func<T, TResult> in Select and Where calls

Suppose I have an entity object defined as

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

Based on some properties of an Article, I need to determine if the article can be deleted by a given user. So I add a static method to do the checking. Something like:

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

So now I can do

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

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

So far so good. Now I want to reuse the logic in CanBeDeletedBy while doing a Select, something like:

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

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

But no matter what I try, I can't use the expression in the select method. I guess that If I can do

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

Then I should be able to use the same expression. Tried to compile the expression and call it by doing

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

but it won't work either.

Any ideas on how to get this to work? Or if it isn't possible, what are the alternatives to reuse business logic in both places?

Thanks

Pedro

like image 542
Pedro Avatar asked Mar 15 '10 11:03

Pedro


1 Answers

Re-using expression trees is a black art; you can do it, but you would need to switch a lot of code to reflection and you'd lose all the static checking. In particular, working with the anonymous types becomes a nightmare (although dynamic in 4.0 might be workable).

Further, if you cheat and use Expression.Invoke, then it isn't supported by all providers (most noticeably not on EF in .NET 3.5SP1).

Unless this is a major pain point, I'd leave it with duplication. Or do you need to re-use the expression tree?

like image 137
Marc Gravell Avatar answered Oct 25 '22 14:10

Marc Gravell