有没有办法获得Sql Server 2005+ Sequential Guid生成器的功能,而无需插入记录来回读往返或调用本机win dll调用?我看到有人回答使用rpcrt4.dll,但我不确定是否可以从我的托管环境中进行生产.
编辑:使用@John Boker的答案我试图把它变成GuidComb生成器的更多,而不是依赖于最后生成的Guid而不是重新开始.对于种子,而不是从我使用的Guid.Empty开始
public SequentialGuid() { var tempGuid = Guid.NewGuid(); var bytes = tempGuid.ToByteArray(); var time = DateTime.Now; bytes[3] = (byte) time.Year; bytes[2] = (byte) time.Month; bytes[1] = (byte) time.Day; bytes[0] = (byte) time.Hour; bytes[5] = (byte) time.Minute; bytes[4] = (byte) time.Second; CurrentGuid = new Guid(bytes); }
我根据评论做了这个
// 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause] // 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause] SqlOrderMap = new[] {3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10};
这看起来像我想用DateTime为guid播种的方式,还是看起来我应该反过来并从SqlOrderMap索引的末尾开始向后工作?我不太关心他们是否会在创建初始guid时进行分页,因为它只会在应用程序回收期间发生.
您可以使用SQL Server使用的相同Win32 API函数:
UuidCreateSequential
并应用一些位移以将值放入big-endian顺序.
因为你想在C#中使用它:
private class NativeMethods { [DllImport("rpcrt4.dll", SetLastError=true)] public static extern int UuidCreateSequential(out Guid guid); } public static Guid NewSequentialID() { //Code is released into the public domain; no attribution required const int RPC_S_OK = 0; Guid guid; int result = NativeMethods.UuidCreateSequential(out guid); if (result != RPC_S_OK) return Guid.NewGuid(); //Endian swap the UInt32, UInt16, and UInt16 into the big-endian order (RFC specified order) that SQL Server expects //See /sf/ask/17360801/ //Short version: UuidCreateSequential writes out three numbers in litte, rather than big, endian order var s = guid.ToByteArray(); var t = new byte[16]; //Endian swap UInt32 t[3] = s[0]; t[2] = s[1]; t[1] = s[2]; t[0] = s[3]; //Endian swap UInt16 t[5] = s[4]; t[4] = s[5]; //Endian swap UInt16 t[7] = s[6]; t[6] = s[7]; //The rest are already in the proper order t[8] = s[8]; t[9] = s[9]; t[10] = s[10]; t[11] = s[11]; t[12] = s[12]; t[13] = s[13]; t[14] = s[14]; t[15] = s[15]; return new Guid(t); }
也可以看看
是否有与SQL Server相同的.NET newsequentialid()
微软UuidCreateSequential
只是一个类型1 uuid 的实现RFC 4122
.
一个uuid有三个重要部分:
node
:(6个字节) - 计算机的MAC地址
timestamp
:(7字节) - 自1582年10月15日00:00:00.00(格里高利改革为基督教历法的日期)以来的100 ns间隔数
clockSequenceNumber
(2个字节) - 计数器,以防你生成一个超过100ns的guid,或者你改变你的mac地址
基本算法是:
获得系统范围的锁定
读取最后一个node
,timestamp
并clockSequenceNumber
从持久存储(注册表/文件)
获取当前node
(即MAC地址)
得到当前 timestamp
a)如果保存的状态不可用或已损坏,或者mac地址已更改,则生成随机 clockSequenceNumber
b)如果状态可用,但当前timestamp
与保存的时间戳相同或更旧,则递增clockSequenceNumber
保存node
,timestamp
并clockSequenceNumber
返回持久存储
释放全局锁
根据rfc格式化guid结构
有一个4位版本号,2位变量也需要与数据进行AND运算:
guid = new Guid( timestamp & 0xFFFFFFFF, //timestamp low (timestamp >> 32) & 0xFFFF, //timestamp mid ((timestamp >> 40) & 0x0FFF), | (1 << 12) //timestamp high and version (version 1) (clockSequenceNumber & 0x3F) | (0x80), //clock sequence number and reserved node[0], node[1], node[2], node[3], node[4], node[5], node[6]);
注意:完全未经测试; 我只是从RFC中看到它.
可能必须更改字节顺序(这是sql server的字节顺序)
您可能想要创建自己的版本,例如版本6(版本1-5已定义).这样你就可以保证普遍独特
这个人想出了一些东西来制作顺序guids,这是一个链接
http://developmenttips.blogspot.com/2008/03/generate-sequential-guids-for-sql.html
相关代码:
public class SequentialGuid { Guid _CurrentGuid; public Guid CurrentGuid { get { return _CurrentGuid; } } public SequentialGuid() { _CurrentGuid = Guid.NewGuid(); } public SequentialGuid(Guid previousGuid) { _CurrentGuid = previousGuid; } public static SequentialGuid operator++(SequentialGuid sequentialGuid) { byte[] bytes = sequentialGuid._CurrentGuid.ToByteArray(); for (int mapIndex = 0; mapIndex < 16; mapIndex++) { int bytesIndex = SqlOrderMap[mapIndex]; bytes[bytesIndex]++; if (bytes[bytesIndex] != 0) { break; // No need to increment more significant bytes } } sequentialGuid._CurrentGuid = new Guid(bytes); return sequentialGuid; } private static int[] _SqlOrderMap = null; private static int[] SqlOrderMap { get { if (_SqlOrderMap == null) { _SqlOrderMap = new int[16] { 3, 2, 1, 0, 5, 4, 7, 6, 9, 8, 15, 14, 13, 12, 11, 10 }; // 3 - the least significant byte in Guid ByteArray [for SQL Server ORDER BY clause] // 10 - the most significant byte in Guid ByteArray [for SQL Server ORDERY BY clause] } return _SqlOrderMap; } } }
以下是NHibernate如何实现Guid.Comb算法:
private Guid GenerateComb() { byte[] guidArray = Guid.NewGuid().ToByteArray(); DateTime baseDate = new DateTime(1900, 1, 1); DateTime now = DateTime.Now; // Get the days and milliseconds which will be used to build the byte string TimeSpan days = new TimeSpan(now.Ticks - baseDate.Ticks); TimeSpan msecs = now.TimeOfDay; // Convert to a byte array // Note that SQL Server is accurate to 1/300th of a millisecond so we divide by 3.333333 byte[] daysArray = BitConverter.GetBytes(days.Days); byte[] msecsArray = BitConverter.GetBytes((long) (msecs.TotalMilliseconds / 3.333333)); // Reverse the bytes to match SQL Servers ordering Array.Reverse(daysArray); Array.Reverse(msecsArray); // Copy the bytes into the guid Array.Copy(daysArray, daysArray.Length - 2, guidArray, guidArray.Length - 6, 2); Array.Copy(msecsArray, msecsArray.Length - 4, guidArray, guidArray.Length - 4, 4); return new Guid(guidArray); }
可以在此处找到经常更新(每毫秒至少3次)的顺序指南.它是使用常规C#代码创建的(没有本机代码调用).