实体框架中集合的高效计数(使用 GROUP BY)

发布于 2024-11-28 11:23:16 字数 711 浏览 1 评论 0原文

我正在使用 Entity Framework 4.1 和 ASP.NET MVC 3。我有两个具有一对多关系的表,比如说 ShopShopVisit,我想要显示商店列表以及访问次数。作为 SQL 查询,执行起来非常简单,但是如何让实体框架有效地执行此操作?

这有效:

_db.Shops.Include("Visits").ToList();


@foreach (var shop in ViewBag.Shops)
{
    Visit count: @shop.Visits.Count
}

但是,查看 SQL Profiler,它似乎使用 LEFT OUTER JOIN 加载所有访问,这不是我想要的。我只想要计数。当然,我也不希望对每个 Shop 进行子查询。我该怎么做才能让它执行 COUNT(*) ... GROUP BY 查询?

即使我执行这样的选择:

_db.Shops.Include("Visits").Select(s => ShopStats { Shop = s, Vists = s.Vists.Count}).ToList();

它仍然坚持执行 LEFT OUTER JOIN,这会加载所有访问。

I'm using Entity Framework 4.1 with ASP.NET MVC 3. I have two tables with a one-to-many relationship, let's say Shop and ShopVisit, and I want to show the list of Shops with the count of Visits. Quite simple to do as an SQL query, but how do I get Entity Framework to do this efficiently?

This works:

_db.Shops.Include("Visits").ToList();


@foreach (var shop in ViewBag.Shops)
{
    Visit count: @shop.Visits.Count
}

However, looking at SQL Profiler, it seems to be loading all Visits using a LEFT OUTER JOIN, which is not what I want. I only want the count. Of course, I don't want a sub-query to be done for each Shop, either. What can I do to make it do a COUNT(*) ... GROUP BY query?

Even if I do a Select like this:

_db.Shops.Include("Visits").Select(s => ShopStats { Shop = s, Vists = s.Vists.Count}).ToList();

It still insists on doing a LEFT OUTER JOIN, which loads all Visits.

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

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

发布评论

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

评论(1

拔了角的鹿 2024-12-05 11:23:16

在这种情况下,您需要创建自定义类型并使用投影:

var data = from s in _db.Shops
           select new SomeCustomType 
               {
                   Shop = s,
                   Count = s.Visits.Count()
               };

您还可以展平 SomeCustomType,以便它将包含 Shop 的所有属性,而不是商店本身。它可能会在查询内部进行左外连接,但不会加载对应用程序的访问。

包含或延迟加载的工作方式如您所描述的那样 - 计数将在内存中计算,因此必须加载所有访问。

编辑:

还有一种解决方案称为超延迟加载。不支持开箱即用,但 您可以扩展 EF 以支持它。在超延迟加载的情况下,您将不会加载Visits,但Count将触发对数据库的查询以获取访问计数。

In such case you need to create custom type and use projection:

var data = from s in _db.Shops
           select new SomeCustomType 
               {
                   Shop = s,
                   Count = s.Visits.Count()
               };

You can also flatten your SomeCustomType so it will contain all properties of Shop instead of shop itself. It will probably do left outer join internally in the query but it will not load visits to the application.

Include or lazy loading works as you described - count will be computed in memory so all visits must be loaded.

Edit:

There is one more solution called extra-lazy loading. It is not supported out of the box but you can extend EF to support it. In case of extra-lazy loading you will not load Visits but Count will trigger query to database to get a count of visits.

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