左外连接linq的结果中的空值会导致错误

pet*_*ter 0 c# linq

我有linq查询,左外连接两个表.我发现如果一个字段的值返回null,那么我将收到一条错误消息:

"转换为值类型'System.Int32'失败,因为具体化值为null.结果类型的泛型参数或查询必须使用可空类型."

我在下面复制了我的linq:

var SrvRef = from s in db.SrvHeads
    join r in db.Referrants on s.svhReferrer equals r.refID into r_join
    from r in r_join.DefaultIfEmpty()
    where s.svhAccID == accId &&
    s.svhHeadCnt == HeadId
    select new
    {
    s.svhBalance,
    r.refID
    };
bool FBeenPaid = SrvRef.FirstOrDefault().svhBalance == 0M; //this causes error
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

Jon*_*eet 8

我对你得到的那种错误感到有些惊讶,但是有两个地方需要考虑结果为null的可能性:

  • 在查询中,where r可以为null.(如果在匹配时没有元素时不想r_join匹配s,则不应使用左外连接)
  • 在结果本身:你正在使用FirstOrDefault()哪个将返回null如果SrvRef为空.

所以乍一看它应该是这样的:

var query = from s in db.SrvHeads
    join r in db.Referrants on s.svhReferrer equals r.refID into r_join
    from r in r_join.DefaultIfEmpty()
    where s.svhAccID == accId && s.svhHeadCnt == HeadId
    select new
    {
        s.svhBalance,
        refId = r == null ? 0 : r.refID // Adjust to the appropriate type of refID
    };
var result = query.FirstOrDefault();
bool beenPaid = result != null && result.svhBalance == 0m;
Run Code Online (Sandbox Code Playgroud)

使用C#6,您可以将底部的两行更改为:

bool beenPaid = query.FirstOrDefault()?.svhBalance == 0m ?? false;
Run Code Online (Sandbox Code Playgroud)

话说回来:

  • 您目前还没有refId在结果中使用- 为什么要在结果中包含它?
  • 你确定你想要一个左外连接吗?
  • 你确定第一个结果真的是你想要的吗?如果加入中有多个结果怎么办?
  • 您是否有任何理由不在查询中执行所有操作?就像是:

    var paid = db.SrvHeads
                 .Where(s => s.svhAccID == accId && s.svhHeadCnt == HeadId)
                 .Any(s => db.Refererrants.Any(r => s.svhReferrer == r.refID
                         && s.svhBalance == 0m);
    
    Run Code Online (Sandbox Code Playgroud)

    ..但只是为了你想要的精确语义.