我在Code TimeStamps的Code First Entity Framework中有一个字节数组,映射如下:
[Column(TypeName = "timestamp")]
[MaxLength(8)]
[Timestamp]
public byte[] TimeStamps { get; set; }
上述属性等于C#中的SQL服务器“timestamp”数据类型。
在SQL server中,我可以轻松比较“timestamp”,如下所示......
SELECT * FROM tableName WHERE timestampsColumnName > 0x000000000017C1A2
我希望在C#或Linq Query中实现同样的功能。在这里,我编写了我的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 Query中比较字节数组。
注意 - 我只是不想比较两个数组,就像使用SequenceEqual或任何其他方法只是比较并返回true或false。我希望Linq查询中的比较大于>或小于<运算符,提供SQL Server查询等适当的数据。
答案 0 :(得分:10)
一种方法是使用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);
现在,如果您使用Entity Framework并且需要比较数据库查询中的时间戳,情况就会有所不同,因为Entity Framework将检查您的查询表达式,寻找它理解的模式。它当然不理解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查询(从表中选择*,其中RowVersion&gt; @yourVersion)
答案 1 :(得分: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