2017-02-28 95 views
4

我在我的代碼優先實體框架的字節數組爲SQL時間戳,映射如下給出:如何在C#或Linq中比較兩個大於或小於運算符值的字節數組?

[Column(TypeName = "timestamp")] 
[MaxLength(8)] 
[Timestamp] 
public byte[] TimeStamps { get; set; } 

以上性能是在C#等於SQL服務器「時間戳」數據類型。

在SQL Server中我可以比較 「時間戳」 容易如下...

SELECT * FROM tableName WHERE timestampsColumnName > 0x000000000017C1A2 

我想在C#或LINQ查詢來實現同樣的事情。在這裏,我寫了我的Linq查詢,這是不正常工作。

byte[] lastTimeStamp = someByteArrayValue; 
lstCostCenter.Where(p => p.TimeStamps > lastTimeStamp); 

我還與BitConverter試圖比較兩個字節數組,也沒有工作...

lstCostCenter.Where(p => BitConverter.ToInt64(p.TimeStamps, 0) > BitConverter.ToInt64(lastTimeStamp, 0)); 

我如何在C#或LINQ查詢比較字節數組。

注 - 我只是不想比較兩個數組,通常像使用SequenceEqual或任何其他方法,只是比較並返回true或false。我希望在大於>或小於<運算符的Linq查詢中進行比較,該運算符可提供適當的數據,如SQL Server查詢。

+3

你想比較使用數據庫(實體框架,LINQ到SQL等)LINQ查詢,或內存中的LINQ查詢? – Evk

+0

字節如何排列在數組中?最重要的字節在先?如果是這樣,然後嘗試使用'.Reverse()調用輸入到'BitConverter.ToInt64'調用的字節。ToArray()' – slawekwin

+0

@Evk我想要與不在內存中的Database Linq Query進行比較。 – Dilip0165

回答

7

一種方法是使用IStructuralComparable,這Array隱含實現:

byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 }; 
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 }; 

var result = ((IStructuralComparable)rv1).CompareTo(rv2, Comparer<byte>.Default); // returns negative value, because rv1 < rv2 

如果你想使用BitConverter某種原因,你必須扭轉陣列,因爲BitConverter是在大多數架構小端(以是安全的 - 你應該檢查BitConverter.IsLittleEndian字段,只有當它返回true時才反轉)。請注意,這樣做效率不高。

var i1 = BitConverter.ToUInt64(rv1.Reverse().ToArray(), 0); 
var i2 = BitConverter.ToUInt64(rv2.Reverse().ToArray(), 0); 

現在,如果您使用實體框架和需要數據庫查詢來比較時間戳,情況有點不同,因爲實體框架將檢查您的查詢表達式尋找它理解模式。它不明白IStructuralComparable比較(當然也有BitConverter轉換),所以你必須使用一個技巧。聲明擴展方法爲字節數組名稱Compare

static class ArrayExtensions { 
    public static int Compare(this byte[] b1, byte[] b2) { 
     // you can as well just throw NotImplementedException here, EF will not call this method directly 
     if (b1 == null && b2 == null) 
      return 0; 
     else if (b1 == null) 
      return -1; 
     else if (b2 == null) 
      return 1; 
     return ((IStructuralComparable) b1).CompareTo(b2, Comparer<byte>.Default); 
    } 
} 

和使用,在EF LINQ查詢:

var result = ctx.TestTables.Where(c => c.RowVersion.Compare(rv1) > 0).ToList(); 

在分析,EF會看到法名Compare和兼容的簽名,並把所到正確的SQL查詢(選擇*從表where RowVersion> @yourVersion)

+0

不知道'Array'實現了'IStructuralComparable'接口:-) – xanatos

+0

ArrayExtension類的方法「比較」解決了我的問題,但爲了更好的可讀性,我可以將「比較」方法重命名爲「ByteArrayCompare」嗎?在Linq中我們已經內置了「Compare」方法。 – Dilip0165

+0

不幸的是,你不能,因爲這就是比較,這使得這個技巧可以工作。使用任何其他名稱將會失敗並顯示NotSupportedException。請注意,您可以使用名稱爲Compare的任何兼容方法,而不需要參數爲字節數組。例如「int Compare(this object b1,object b2)」也可以。 – Evk

0

如果你知道兩個字節數組是相等的長度和最重要的字節第一然後這工作:

Func<byte[], byte[], bool> isGreater = 
    (xs, ys) => 
     xs 
      .Zip(ys, (x, y) => new { x, y }) 
      .Where(z => z.x != z.y) 
      .Take(1) 
      .Where(z => z.x > z.y) 
      .Any(); 

如果我用下面的測試:

byte[] rv1 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01 }; 
byte[] rv2 = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x05 }; 

Console.WriteLine(isGreater(rv1, rv2)); 
Console.WriteLine(isGreater(rv2, rv1)); 

...我得到的預期結果如下:

 
False 
True 
相關問題