如何使Sum()返回0而不是'null'?

时间:2018-10-09 13:14:44

标签: c# sql-server entity-framework linq linq-to-entities

我正在尝试使用LINQ-to-entities查询我的数据库,其中有3个表:RoomConferenceParticipant。每个房间都有很多会议,每个会议都有很多参与者。对于每个房间,我正在尝试统计其会议数量,以及该房间所有会议的所有参与者的总和。这是我的查询:

var roomsData = context.Rooms
    .GroupJoin(
        context.Conferences
            .GroupJoin(
                context.Participants,
                conf => conf.Id,
                part => part.ConferenceId,
                (conf, parts) => new { Conference = conf, ParticipantCount = parts.Count() }
            ),
        rm => rm.Id,
        data => data.Conference.RoomId,
        (rm, confData) => new {
            Room = rm,
            ConferenceCount = confData.Count(),
            ParticipantCount = confData.Sum(cd => cd.ParticipantCount)
        }
    );

当我尝试将其转换为列表时,出现错误:

  

强制转换为值类型'System.Int32',因为物化值为null。结果类型的通用参数或查询必须使用可为空的类型。

我可以通过将Sum行更改为以下内容来解决此问题:

ParticipantCount = confData.Count() == 0 ? 0 : confData.Sum(cd => cd.ParticipantCount)

但是麻烦的是,这似乎会生成更复杂的查询,并使查询时间增加100ms。我有没有更好的办法告诉EF,当它求和ParticipantCount时,confData的空列表应该只是零,而不是抛出异常?令人讨厌的是,此错误仅在EF中发生;如果我创建一个空的内存List<int>并在其上调用Sum(),它将给我零,而不是引发异常!

4 个答案:

答案 0 :(得分:0)

使用Enumerable.DefaultIfEmpty

 ParticipantCount = confData.DefaultIfEmpty().Sum(cd => cd.ParticipantCount)

答案 1 :(得分:0)

您可以使用null coalescing operator?为:

confData.Sum(cd => cd.ParticipantCount ?? 0)

答案 2 :(得分:0)

我将Sum行更改为:

ParticipantCount = (int?)confData.Sum(cd => cd.ParticipantCount)

令人困惑的是,即使IntelliSense告诉我int的{​​{1}}重载已被使用,但在运行时它实际上仍在使用Sum()重载,因为{{1} }列表可能为空。如果我明确告诉它返回类型为int?,则它为空列表条目返回confData,稍后我可以将int?的值空置为零。

答案 3 :(得分:0)

您不会像试图让EF来生成返回0而不是null的SQL查询那样,而是在像这样处理客户端的查询结果时进行更改:

var results = from r in roomsData.AsEnumerable()
              select new 
              {
                r.Room,
                r.ConferenceCount,
                ParticipantCount = r.ParticipantCount ?? 0
              };

AsEnumerable()强制对SQL查询进行求值,随后的查询运算符为客户端LINQ-to-Objects。