代码之家  ›  专栏  ›  技术社区  ›  letmaik

如何在linq中使用ef4(和linqkit)的外部表达式?

  •  2
  • letmaik  · 技术社区  · 16 年前

    我想分离出linq查询中常用的表达式。我正在使用EntityFramework4和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 回复  |  直到 16 年前
        1
  •  1
  •   Alex James    16 年前

    问题是ef不支持invoke表达式,所以需要以不同的方式将表达式折叠到ef中。

    你应该去达米恩家看看 Client-Side properties “这篇文章基本上满足了你的要求。

    想了解更多的背景信息,请查看colin meek的帖子,其中展示了如何访问和替换 Invoke expressions with expressions EF can handle .

    希望这有帮助

    亚历克斯

        2
  •  1
  •   Community Mohan Dere    9 年前

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

    当我通读时 this ,很明显,我只是想找到一个错误问题的解决方案。让我解释一下……

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

    当我开始思考“如果我不使用延迟加载,那会怎么样?”简单地说,我想要的所有数据都是从一开始就获取的,然后您就可以对这些数据进行操作,而不需要对其他任何数据进行操作,也就是说,没有隐藏的查询。当以这种方式看待它时,在域对象的关系上使用ICollection而不是IQueryable是有意义的。当然,对于icollection的.where()调用,我不能使用表达式,而是使用内部func<..>。

    要回答我自己的问题,expression<>只能在访问存储库或知道poco对象不是存储库时使用。如果它们应该在外部(即在ICollection上)使用,则必须对它们进行编译以使对象具有如下功能:

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

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

    我对此几乎满意。我觉得烦人的是需要调用“.compile()”,我仍然不明白的是,我应该如何构造或让一个表达式使用另一个表达式,除了调用.compile()之外,这个表达式似乎是不可能的,因为它又是唯一一个我无法放置的ICollection表达式对象。我想在这里我可以使用linqkit,然后去掉compile()调用。

    我希望我的方向是正确的。如果你发现任何逻辑错误或能想出更好的方法,请在评论中告诉我,以便我可以更新答案。谢谢大家!

        3
  •  0
  •   Chao    16 年前

    在使用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
            }
        }
     }