I was surprised not to find a half-decent answer to this problem anywhere when I looked over the last few weeks.
The main problem with LSNs is that they are 10 bytes, so they can't simply be converted to Int64
and compared (aside: will you really generate that many LSNs?! Int64
is really big). And as the OP discovered, comparing the bytes one-by-one is a bit painful/error prone (comparing for equality is fine - comparing for greater-than/less-than less so). However, as of .Net Framework 4 we have the BigInteger
class, which can be used to easily compare integers exceeding 8 bytes.
So the problem is just how to get the varbinary(10) from a LSN into a BigInteger. From inspection[1] it appears that SQL stores the LSN in big-endian format, so you have to:
- get the
varbinary(10)
into memory. LinqToSql will give you Binary
, other providers will map to byte[] directly.
- flip the bytes, if you are on little-endian architecture (hint: you are).
IEnumerable.Reverse().ToArray()
will do that if you don't want to do a reverse-loop yourself
- call
new BigInteger(bytes)
- compare the values at your leisure
This might look something like this:
// 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] I made sequential changes, and looked at the LSNs. The last byte was clearly incrementing, hence big-endian.