使用一个LINQ查询计算属性中的空值

时间:2016-08-16 11:21:38

标签: linq count

粘贴到LINQPad:

void Main()
{
    List<Data> list = new List<Data>();
    list.Add(new Data());
    list.Add(new Data{a="a", b="b"});
    list.Add(new Data{a=null, b="b"});

    var queryA = from data in list where data.a == null select data;
    var queryB = from data in list where data.b == null select data;

    var countNulls = new {a = queryA.Count(),b = queryB.Count()};
    countNulls.Dump();
}

class Data
{
    public string a {get;set;}
    public string b {get;set;}
}

可以在一个查询中执行此操作而不是使用queryA和queryB吗?

答案
下面的所有查询都会生成完全相同的SQL,所以它只是编码器的首选项。

var countNulls = new 
    { 
        a = queryA.Count(), 
        b = queryB.Count() 
    };

    var countNulls2 = new 
    { 
        a = list.Count(d => d.a == null), 
        b = list.Count(d => d.b == null) 
    };

    var countNulls3 = list.Aggregate(
    new { a = 0, b = 0 },
    (acc, data) => new
    {
        a = acc.a + (data.a == null ? 1 : 0),
        b = acc.b + (data.b == null ? 1 : 0),
    });

更新:显然(感谢Evan Stoev)这项任务可以在EF的DbSet上快20倍,并创建一个SQL查询。

var countNulls4 =
    (from data in db.Data
     group data by 1 into g
     select new
     {
         a = g.Sum(data => data.a == null ? 1 : 0),
         b = g.Sum(data => data.b == null ? 1 : 0)
     }).First();

1 个答案:

答案 0 :(得分:2)

为了完整性,您可以使用Aggregate在输入序列中一次性获取结果:

var countNulls = list.Aggregate(
    new { a = 0, b = 0 },
    (acc, data) => new
    {
        a = acc.a + (data.a == null ? 1 : 0),
        b = acc.b + (data.b == null ? 1 : 0),
    });

但是我不确定与2个单独的Count调用相比,它会更有效率,因为每个步骤都需要匿名对象分配。

更新:事实证明,您要求进行单个SQL查询(因此list实际上不是List<Data>,而是DbSet<Data>我猜。在LINQ to Entities中,您可以使用 group by constant 技术,结合使用Count(condition)替换Sum(condition ? 1 : 0)将生成一个很好的单个SQL查询,非常类似于您手动编写的内容:

var countNulls =
    (from data in db.Data
     group data by 1 into g
     select new
     {
         a = g.Sum(data => data.a == null ? 1 : 0),
         b = g.Sum(data => data.b == null ? 1 : 0)
     }).First();