【问题标题】:Query with Nullable Values using LINQ使用 LINQ 查询可空值
【发布时间】:2012-12-30 16:36:18
【问题描述】:

我试图弄清楚如何在 LINQ 中进行查询,其中某些值可以为空。

接下来是我的桌子:

ID int
Key1 int
Key2 int?
Key3 int?
Value string

uniq = Key1+Key2+Key3+Value

现在我需要根据唯一约束检查​​现有记录是否已经存在。

我尝试了以下方法:

Object tmp = model.table.FirstOrDefault(row => row.Key1 == newItem.Key1 &&
             (row.Key2.HasValue && newItem.Key2.HasValue && row.Key2.Value == newItem.Key2.Value) &&
             (row.Key3.HasValue && newItem.Key3.HasValue && row.Key3.Value == newItem.Key3.Value) &&
             row.Value == newItem.Value);

和:

Object tmp = model.table.FirstOrDefault(row => row.Key1 == newItem.Key1 &&
             row.Key2 == newItem.Key2 &&
             row.Key3 == newItem.Key3 &&
             row.Value == newItem.Value);

但是当其中一个键为空时,两者都没有给我正确的结果!

有没有办法编写正确的 LINQ 查询?

【问题讨论】:

  • 如果row.Key2newItem.Key2 都为空,结果是否应该出现在tmp 中?
  • 是的!我只是意识到第一个查询是错误的。如果一行 (1,222,null,null,3)... 并且我正在使用相同的数据进行查询,则应该返回
  • 太棒了。没有其他问题了吗?
  • 问题还在...

标签: c# .net linq


【解决方案1】:
object tmp= model.table.FirstOrDefault(t => 
    t.Key1 == newItem.Key1 
    && ((!t.Key2.HasValue & !newItem.Key2.HasValue) 
        | t.Key2.Value == newItem.Key2.Value)                             
    && ((!t.Key3.HasValue & !newItem.Key3.HasValue) 
        | t.Key3.Value == newItem.Key3.Value) && t.Value == newItem.Value);

【讨论】:

  • 你不需要比较空值的函数。
  • 如果你添加价值计算......这就是我需要的!
  • 你能解释一下是什么意思吗?和 & 在我们的例子中?
  • 由于HasValue 和比较都是布尔操作数,所以使用位运算符(&,|)是没有意义的。你真的应该使用标准的布尔运算符(见这里:stackoverflow.com/questions/24542/…)。
  • 无论如何,正如我在答案末尾(编辑 2)所写的那样,您可以简单地使用 == 而无需检查您的变量 hasValue,至少这对 C# 有效。
【解决方案2】:

前段时间,我写了一个小函数来处理这种情况:

Private Function EqualOrBothNull(ByVal int1 As Int32?, ByVal int2 As Int32?) As Boolean
    Select Case True
        Case (int1 Is Nothing AndAlso int2 Is Nothing)
            Return True
        Case (int1 Is Nothing AndAlso int2 IsNot Nothing) OrElse (int1 IsNot Nothing AndAlso int2 Is Nothing)
            Return False
        Case (int1 IsNot Nothing AndAlso int2 IsNot Nothing)
            Return int1 = int2
    End Select
End Function

它在 VB.NET 中,但在 C# 中转换应该很简单:

private bool EqualOrBothNull(Nullable<Int32> int1, Nullable<Int32> int2) {
    switch (true) {
        case (int1 == null && int2 == null):
            return true;
        case (int1 == null && int2 != null) || (int1 != null && int2 == null):
            return false;
        case (int1 != null && int2 != null):
            return int1 == int2;
    }
}

那么,你可以简单地写:

Object tmp = model.table.FirstOrDefault(row =>
                      EqualOrBothNull(row.Key1, newItem.Key1) &&
                      EqualOrBothNull(row.Key2, newItem.Key2) &&
                      EqualOrBothNull(row.Key3, newItem.Key3) &&
                      EqualOrBothNull(row.Value, newItem.Value));

回复几位cmet对我的回答:

至少在 VB.NET 中,如果其中至少一个具有无值:

不,a = b 不仅仅是 VB.NET 中的赋值。

运算符= 由编译器在赋值比较之间自动切换。

此外,在 Quickwatch 模式中,它总是被解析为比较。

C# 的行为与 VB 不同:

刚刚检查过,在 C# 中,简单的 == 操作数的行为与您期望的一样(如 Ilya IvanovKonrad Morawski 在 cmets 中出现),所以有 在这个问题的场景中不需要使用 HasValue。

【讨论】:

  • 为什么不在int? 操作数上使用== 运算符。如果一个操作数为 null 而另一个不是 - 它将返回 false。如果两者都为 null - 返回 true。如果两者都不为 null - 它将比较值。
  • 如果两者都为 null 则不返回 true!
  • Console.WriteLine (null == null); //true。我错过了什么吗?
  • 是的,但是两个 Int32?两个 null 的行为都不一样,因为它们是引用,而不是原始类型。
  • 你检查过吗? Console.WriteLine((int?)null == (int?)null); // true... Nullable&lt;Int32&gt; a = null; Nullable&lt;Int32&gt; b = null; Console.WriteLine(a == b); 给出相同的效果
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-09
  • 2023-03-17
  • 1970-01-01
相关资源
最近更新 更多