Я был удивлен, что нигде не нашел приличного ответа на эту проблему, когда просматривал последние несколько недель.
Основная проблема с номерами LSN состоит в том, что они имеют размер 10 байт, поэтому их нельзя просто преобразовать в Int64
и сравнить (кроме того: вы действительно сгенерируете такое количество номеров LSN?! Int64
действительно большой). И как обнаружил OP, сравнение байтов один за другим немного болезненно / подвержено ошибкам (сравнение на равенство - это хорошо - сравнение на большее / меньшее, чем меньшее). Однако в .Net Framework 4 у нас есть класс BigInteger
, который можно использовать для простого сравнения целых чисел, превышающих 8 байтов.
Так что проблема в том, как получить varbinary (10) из LSN в BigInteger. Из проверки [1] видно, что SQL хранит LSN в формате с прямым порядком байтов, поэтому вам необходимо:
- получить
varbinary(10)
в память. LinqToSql выдаст вам Binary
, другие провайдеры будут напрямую сопоставлены с байтом [].
- перевернуть байты, если вы используете архитектуру с прямым порядком байтов (подсказка: вы есть).
IEnumerable.Reverse().ToArray()
сделает это, если вы не хотите делать обратный цикл самостоятельно
- звоните
new BigInteger(bytes)
- сравните значения на досуге
Это может выглядеть примерно так:
// https://gist.github.com/piers7/91141f39715a2ec133e5
// Example of how to interpret SQL server CDC LSNs in C# / .Net
// This is required when polling a server for updates in order to determine
// if a previously stored LSN is still valid (ie > min LSN available)
// Requires .Net 4 (or equivilent BigInteger implementation)
// Sample is a Linqpad script, but you get the idea
// NB: That SQL uses big-endian representation for it's LSNs is not
// (as best I know) something they guarantee not to change
Connection.Open();
var command = Connection.CreateCommand();
command.CommandText = @"select sys.fn_cdc_get_max_lsn() as maxLsn";
var bytes = (byte[])command.ExecuteScalar();
// dump bytes as hex
var hexString = string.Join(" ", bytes.Select(b => b.ToString("X2")))
.Dump("Hex String");
if(BitConverter.IsLittleEndian)
bytes = bytes.Reverse().ToArray();
var bigInt = new BigInteger(bytes)
// dump Integer representation
.Dump("Big Integer")
;
[1] Я внес последовательные изменения и посмотрел на номера LSN. Последний байт был явно инкрементным, следовательно, big-endian.