如何计算活动和非活动统计信息而不加载表的所有数据?

时间:2016-10-06 15:36:21

标签: c# entity-framework linq

我有这个型号:

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Nullable<bool> IsActive { get; set; }
}

我正在尝试计算这2个统计数据:

1)活跃类别

2)非活动类别

var query = context.Category.ToList();
var categoriesStats = (new
{
    active = query.Where(t => t.IsActive).Count(),
    inactive = query.Where(t => !t.IsActive).Count(),
});

是否可以在不加载所有类别数据然后计算活动和非活动统计数据的情况下执行此操作?

4 个答案:

答案 0 :(得分:4)

与往常一样,您可以使用group by 常量技术通过单个数据库查询获取结果。

如果您使用Sum(condition ? 1 : 0)而不是Count(condition)(或Where(condition).Count()),您还可以获得更好的SQL翻译。

var categoriesStats = (
    from c in context.Category
    group c by 1 into g
    select new
    {
        active = g.Sum(e => e.IsActive == true ? 1 : 0),
        inactive = g.Sum(e => e.IsActive != true ? 1 : 0),
    }).FirstOrDefault();

答案 1 :(得分:3)

var query = context.Category;
var categoriesStats = new
{
    active = query.Count(t => t.IsActive),
    inactive = query.Count(t => !t.IsActive)
};
  1. 不要使用ToList,这将从数据库中实现整个DbSet。
  2. 直接使用Count,不需要在哪里。

答案 2 :(得分:2)

您可以在一个查询中执行此操作,如下所示:

var counts = context
    .Category
    .GroupBy(t => t.IsActive ?? false).ToDictionary(
        g => g.Key
    ,   g => g.Count()
    );
var res = new {
    Active = counts.ContainsKey(true) ? counts[true] : 0
,   Inactive = counts.ContainsKey(false) ? counts[false] : 0
};

与使用context.Category两次的方法不同,使用GroupBy的方法只需向数据库进行一次往返即可同时获取两个计数。计数将在RDBMS端完成,因此您不需要将所有类别加载到内存中。

答案 3 :(得分:1)

删除ToList

var query = context.Category;
var categoriesStats = new
{
    active = query.Count(t => t.IsActive),
    inactive = query.Count(t => !t.IsActive),
};

在开头ToList()执行查询select * from category。如果没有它,您现在将获得2个查询:select count(*) from category where isActive = 1,另一个查询。 虽然这会导致数据库发送2轮,但返回的数据量只是计数的int而不是对象的所有记录。

使用GroupBy

的另一个选择,就是这种方式只需一次
from c in context.Category
group c by ((c.IsActive ?? false) ? "Active" : "Inactive") into g
select new { State = g.Key, Amount = g.Count() }