如何在Linq中使用EF4(和LINQKit)中的外部表达式?

时间:2010-03-30 09:28:30

标签: linq entity-framework linq-to-entities lambda

我想在linq查询中分离常用的表达式。我正在使用Entity Framework 4和LINQKit,但我仍然不知道我应该如何以正确的方式做到这一点。让我举个例子:

Article article = dataContainer.Articles.FirstOrDefault(a => a.Id == id);

IEnumerable<Comment> comments =
  (from c in article.Comments
   where CommentExpressions.IsApproved.Invoke(c)
   select c);


public static class CommentExpressions
{
    public static Expression<Func<Comment, bool>> IsApproved
    {
        get
        {
            return c => c.IsApproved;
        }
    }
}

当然,IsApproved表达式会更加复杂。

问题是Invoke()不起作用,因为我没有在container.Comments上从LINQKit调用.asExpandable()但是我不能调用它,因为它只是一个ICollection而不是ObjectSet。

所以我的问题是:当我想要包含外部表达式时,我是否总是必须通过数据上下文,或者我可以以某种方式在我获取的对象上使用它(文章)?

任何想法或最佳做法? 非常感谢! 新

3 个答案:

答案 0 :(得分:1)

问题是EF不支持Invoke表达式,因此您需要以不同的方式将表达式折叠到EF中。

你应该查看Damien的'Client-Side properties'帖子,它基本上是你所要求的。

有关更多背景信息,请查看Colin Meek的帖子,了解如何访问和替换Invoke expressions with expressions EF can handle

希望这有帮助

亚历

答案 1 :(得分:1)

我想我找到了我的“问题”的答案。我的问题不是一个问题,而是一种错误的思维方式。

当我通读this时,我清楚地知道我只是想找到一个解决错误问题的方法。让我解释一下......

我正在使用带有EF4的POCO模板,并且仍然激活了延迟加载。有了这个,我可以神奇地遍历对象而不发送额外的查询,至少它们在我的代码中不可见。但是,当然,对于每次访问关系,都会发送查询,我也会使用EF Profiler观察这些查询。当然,我也希望以最佳方式使用它们,即“使用该sql中的where条件”而不是“获取所有行并在之后进行过滤”。这种思维方式也称为过早优化。

当我开始思考“如果我不使用延迟加载会怎样?”时,它终于打动了我。很简单,我想要的所有数据都是在第一个位置获取的,之后您对该数据进行操作,而不是其他任何数据,即没有隐藏的查询。以这种方式查看它时,在域对象的关系中使用ICollection而不是IQueryable是有意义的。当然我不能使用Expression&gt;对于ICollection上的.Where()调用,而不是内部Func&lt; ..&gt ;.

要回答我自己的问题,只有在访问存储库或意识到POCO对象不存在时才能使用Expression&lt;&gt;。如果它们应该在外部使用,即在ICollection上使用,则必须将它们编译为Func对象:

IEnumerable<Comment> comments =
  (from c in article.Comments
   select c).Where(CommentExpressions.IsApproved.Compile());

如果确实需要高性能,则必须要求存储库通过匹配ID以及满足CommentExpressions.IsApproved的位置来获取属于该文章的所有注释。这样的事情:

IEnumerable<Comment> comments =
  (from c in dataContainer.ArticleComments
   where c.ArticleId == article.Id
   select c).Where(CommentExpressions.IsApproved);

现在最后一个where条件由于缺少.compile()而保留了Expression,并且可以在sql中使用。

我对此非常满意。我觉得烦人的是需要调用“.compile()”而我仍然不明白的是我应该如何构造或让一个Expression使用另一个似乎不可能的表达式,除非通过调用.compile()包括它,因为它再次只有ICollection我不能把Expression对象。我想在这里我可以使用LINQKit,然后删除compile()调用。

我希望我朝着正确的方向前进。如果您发现任何逻辑错误或者可以考虑更好的方法,请在评论中告诉我,以便我可以更新答案。谢谢大家!

答案 2 :(得分:0)

在使用LinqKit时,请使用谓词构建器:

IEnumerable<Comment> comments =
  article.Comments.Where(CommentExpressions.IsApproved).Select(c=>c);

 public static class CommentExpressions
 {
    public static Expression<Func<Module, bool>> IsApproved
    {
        get
        {
            var pred = PredicateBuilder.True<Module>();
            pred = pred.And(m => m.IsApproved);
            return pred
        }
    }
 }