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

发布于 2024-08-26 22:02:50 字数 787 浏览 4 评论 0原文

我想分离出 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() 不起作用,因为我没有从 LINQKit 上的 container.Comments 调用 .asExpandable() 但我无法调用它,因为它只是一个 ICollection 而不是 ObjectSet。

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

有什么想法或最佳实践吗? 非常感谢! 新

I want to separate out often used expressions in linq queries. I'm using Entity Framework 4 and also LINQKit but I still don't know how I should do it the right way. Let me give you an example:

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

Of course the IsApproved expression would be something much more complicated.

The problem is that the Invoke() won't work because I didn't call .asExpandable() from LINQKit on container.Comments but I can't call it because it's just an ICollection instead of an ObjectSet.

So my question is: Do I always have to go through the data context when I want to include external expressions or can I somehow use it on the object I fetched (Article)?

Any ideas or best practices?
Thanks very much!
neo

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏末染殇 2024-09-02 22:02:50

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

您应该查看 Damien 的 '客户端属性'帖子基本上满足了您的要求。

有关更多背景信息,请查看 Colin Meek 的帖子,其中展示了如何访问和替换 使用 EF 可以处理的表达式调用表达式

希望这对

亚历克斯有帮助

The problem is EF doesn't support Invoke expressions, so you need to fold the expression into the EF in a different way.

You should check out Damien's 'Client-Side properties' post which does basically what you are asking for.

And for more background information check out Colin Meek's post showing how to visit and replace Invoke expressions with expressions EF can handle.

Hope this helps

Alex

爱本泡沫多脆弱 2024-09-02 22:02:50

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

当我通读这个,我很清楚我只是想找到一个错误问题的解决方案。让我解释一下......

我正在将 POCO 模板与 EF4 一起使用,并且延迟加载仍然处于激活状态。有了这个,我可以神奇地遍历这些对象,而无需发送额外的查询,至少它们在我的代码中不可见。当然,对于每次访问关系,都会发送查询,我还使用 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());

则必须将它们编译为 Func 对象,如下所示: 如果确实需要高性能,则必须要求存储库获取属于该文章的所有评论匹配 ID 以及满足 CommentExpressions.IsApproved 的位置。就像这样:

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

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

我对此已经基本满意了。我觉得烦人的是需要调用“.compile()”,而我仍然不明白的是我应该如何构造或让一个表达式使用另一个表达式,除了调用 .compile() 之外,这似乎是不可能的同时包含它,因为它又只是 ICollection,我无法在其上放置 Expression 对象。我想在这里我可以使用 LINQKit,然后它会删除compile() 调用。

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

I think I found an answer to my "problem". My problem wasn't really a problem but rather a wrong way of thinking.

When I read through this, it came clear to me that I just wanted to find a solution for a wrong problem. Let me explain that....

I'm using the POCO template with EF4 and have lazy loading still activated. With this I could magically walk through the objects without sending additional queries, at least they were not visible in my code. But of course, for each access to a relationship, queries were sent, and I also observed these with EF Profiler. And of course I also wanted to have them in their optimal way, i.e. "use the where condition in that sql" instead of "fetch all rows and do the filtering afterwards". This way of thinking is also called premature optimization.

It finally hit me when I started thinking "How would it be if I don't use lazy loading?" Simple, all data I want is fetched in the first place and afterwards you operate on that data and on nothing else, i.e. no hidden queries. When looking at it this way it makes sense to have ICollection instead of IQueryable on your domain object's relationships. And of course I can't use an Expression> for a .Where() call on a ICollection, but rather the inner Func<..>.

To answer my own question, Expression<>'s must only be used while having access to the repository or being aware of it which the POCO objects are not. If they should be used outside, i.e. on a ICollection, they have to be compiled to Func objects like that:

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

And if there really is a need for high performance then the repository has to be asked to fetch all the comments belonging to that article by matching on the ID and where CommentExpressions.IsApproved is fulfilled. Something like that:

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

Now the last where condition retains an Expression because of the missing .compile() and can be used in the sql.

I'm nearly satisfied with this. What I find annoying is the need to call ".compile()" and what I still don't understand is how I should construct or let one Expression use another expression which doesn't seem to be possible except by calling .compile() while including it because it's again only ICollection on which I cannot put Expression objects. I suppose here I can use LINQKit which then strips out the compile() calls.

I hope I'm going in the right direction. If you spot any logical error or can think of better ways doing that, please tell me in the comments so I can update the answer. Thanks all!

沫尐诺 2024-09-02 22:02:50

当您使用 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
        }
    }
 }

As you are using LinqKit use the predicate builder:

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
        }
    }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文