如何在不加载表的所有数据的情况下计算活动和非活动统计信息



我有这个型号:

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(),
});

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

与通常的多个聚合一样,您可以使用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();
var query = context.Category;
var categoriesStats = new
{
    active = query.Count(t => t.IsActive),
    inactive = query.Count(t => !t.IsActive)
};
  1. 不要使用ToList,这会从数据库中具体化整个DbSet
  2. 直接使用Count,不需要在哪里

您可以在单个查询中完成,如下所示:

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端完成,因此不需要将所有类别加载到内存中。

删除ToList:

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

在开始时具有ToList()执行将是select * from category的查询。如果没有它,您现在将获得两个查询:select count(*) from category where isActive = 1和一个用于另一个。尽管这导致了对数据库的两次循环,但返回的数据量只是计数的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() }

相关内容