实体框架中集合的高效计数(使用 GROUP BY)
我正在使用 Entity Framework 4.1 和 ASP.NET MVC 3。我有两个具有一对多关系的表,比如说 Shop 和 ShopVisit,我想要显示商店列表以及访问次数。作为 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在这种情况下,您需要创建自定义类型并使用投影:
您还可以展平
SomeCustomType
,以便它将包含Shop
的所有属性,而不是商店本身。它可能会在查询内部进行左外连接,但不会加载对应用程序的访问。包含或延迟加载的工作方式如您所描述的那样 - 计数将在内存中计算,因此必须加载所有访问。
编辑:
还有一种解决方案称为超延迟加载。不支持开箱即用,但 您可以扩展 EF 以支持它。在超延迟加载的情况下,您将不会加载
Visits
,但Count
将触发对数据库的查询以获取访问计数。In such case you need to create custom type and use projection:
You can also flatten your
SomeCustomType
so it will contain all properties ofShop
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
butCount
will trigger query to database to get a count of visits.