Повторное использование Linq для выражения сущностей <Func <T, TResult> в вызовах Select и Where - PullRequest
13 голосов
/ 15 марта 2010

Предположим, у меня есть объект сущности, определенный как

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

Пока все хорошо. Теперь я хочу повторно использовать логику в CanBeDeletedBy при выполнении выбора, что-то вроде:

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

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

Но что бы я ни пытался, я не могу использовать выражение в методе выбора. Я думаю, что если я могу сделать

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

но это тоже не сработает.

Есть идеи, как заставить это работать? Или, если это невозможно, каковы альтернативы повторного использования бизнес-логики в обоих местах?

Спасибо

Pedro

Ответы [ 2 ]

4 голосов
/ 15 марта 2010

Повторное использование деревьев выражений - это черное искусство; Вы можете сделать это, но вам нужно будет переключить много кода на отражение, и вы потеряете всю статическую проверку. В частности, работа с анонимными типами становится кошмаром (хотя dynamic в 4.0 может быть работоспособным).

Кроме того, если вы обманываете и используете Expression.Invoke, то это поддерживается не всеми провайдерами (наиболее заметно не в EF в .NET 3.5SP1).

Если это не главная проблема, я бы оставил это с дублированием. Или вам нужно для повторного использования дерева выражений?

3 голосов
/ 03 ноября 2010

Что я сделал, так это то, что я использовал PredicateBuilder, который является классом в LinqKit, а также AsExpandable () http://www.albahari.com/nutshell/linqkit.aspx для построения выражений, и я их статически хранил как

public readonly Expression<Func<T,bool>>

в статическом классе. Каждое выражение основывалось на предыдущем выражении, тем самым уменьшая количество повторений.

Как показывает предыдущий вопрос Марка Гравелла, это своего рода черное искусство, но, к счастью, большая часть работы была проделана другими людьми.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...