1

一部の値がnull許容である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);

しかし、キーの1つがヌルの場合、どちらも正しい結果を得ることができませんでした。

正しいLINQクエリを作成する方法はありますか?

4

2 に答える 2

2
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);
于 2013-01-16T11:54:48.717 に答える
1

少し前に、このような状況を処理するための小さな関数を作成しました。

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));

私の答えに対するいくつかのコメントに返信するには:

少なくともVB.NETでは、2つのNullable(Of T)の比較は常にブール値に評価されますか?それらの少なくとも1つに値がない場合、値はNothingになります。

ここに画像の説明を入力してください

いいえ、a = bVB.NETでの割り当てだけではありません。

演算子は、割り当て比較=の間でコンパイラによって自動切り替えされるコンテキストベースです。

さらに、クイックウォッチモードでは、常に比較として解析されます。

C#はVBとは異なる動作をします。

確認したところ、C#では、単純な==オペランドが期待どおりに機能するため(IlyaIvanovKonradMorawskiがコメントで判明したように)、この質問のシナリオでHasValueを使用する必要はありません。

于 2013-01-16T11:47:09.560 に答える