SequentialGuidGenerator.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Security.Cryptography;
  6. namespace EasyDevCore.Common
  7. {
  8. /// <summary>
  9. ///
  10. /// </summary>
  11. public enum SequentialGuidType
  12. {
  13. /// <summary>
  14. /// The sequential as string (sepecific for MySQL, PostgreSQL ...)
  15. /// </summary>
  16. SequentialAsString,
  17. /// <summary>
  18. /// The sequential as binary (sepecific for Oracle)
  19. /// </summary>
  20. SequentialAsBinary,
  21. /// <summary>
  22. /// The sequential at end (sepecific for Microsoft SQL Server)
  23. /// </summary>
  24. SequentialAtEnd
  25. }
  26. /// <summary>
  27. ///
  28. /// </summary>
  29. public static class SequentialGuidGenerator
  30. {
  31. /// <summary>
  32. /// The _RNG
  33. /// </summary>
  34. private static readonly System.Security.Cryptography.RandomNumberGenerator _rng = System.Security.Cryptography.RandomNumberGenerator.Create();
  35. /// <summary>
  36. /// Create a sequential GUID.
  37. /// </summary>
  38. /// <param name="guidType">Type of the GUID.</param>
  39. /// <returns></returns>
  40. public static Guid NewSequentialGuid(SequentialGuidType guidType)
  41. {
  42. return NewSequentialGuid(guidType, 1)[0];
  43. }
  44. /// <summary>
  45. /// Nexts the sequential unique identifier.
  46. /// </summary>
  47. /// <param name="guid">The unique identifier.</param>
  48. /// <param name="guidType">Type of the unique identifier.</param>
  49. /// <returns></returns>
  50. public static Guid NextSequentialGuid(Guid guid, SequentialGuidType guidType)
  51. {
  52. byte[] guidBytes = guid.ToByteArray();
  53. UInt32 nextID = 0;
  54. switch (guidType)
  55. {
  56. case SequentialGuidType.SequentialAsString:
  57. case SequentialGuidType.SequentialAsBinary:
  58. nextID = BitConverter.ToUInt32(guidBytes, 12) + 1;
  59. Buffer.BlockCopy(BitConverter.GetBytes(nextID), 0, guidBytes, 12, 4);
  60. break;
  61. case SequentialGuidType.SequentialAtEnd:
  62. nextID = BitConverter.ToUInt32(guidBytes, 6) + 1;
  63. Buffer.BlockCopy(BitConverter.GetBytes(nextID), 0, guidBytes, 6, 4);
  64. break;
  65. default:
  66. throw new NotSupportedException(guidType.ToString());
  67. }
  68. return new Guid(guidBytes);
  69. }
  70. /// <summary>
  71. /// Nexts the sequential unique identifier.
  72. /// </summary>
  73. /// <param name="guid">The unique identifier.</param>
  74. /// <returns></returns>
  75. public static Guid NextSequentialGuid(Guid guid)
  76. {
  77. return NextSequentialGuid(guid, SequentialGuidType.SequentialAtEnd);
  78. }
  79. /// <summary>
  80. /// Create a sequential GUID (sepecific for Microsoft SQL Server)
  81. /// (SequentialGuidType = SequentialGuidType.SequentialAtEnd).
  82. /// </summary>
  83. /// <returns></returns>
  84. public static Guid NewSequentialGuid()
  85. {
  86. return NewSequentialGuid(SequentialGuidType.SequentialAtEnd, 1)[0];
  87. }
  88. /// <summary>
  89. /// Create a sery sequential GUIDs (sepecific for Microsoft SQL Server)
  90. /// (SequentialGuidType = SequentialGuidType.SequentialAtEnd).
  91. /// </summary>
  92. /// <param name="count">The count.</param>
  93. /// <returns></returns>
  94. public static Guid[] NewSequentialGuid(int count)
  95. {
  96. return NewSequentialGuid(SequentialGuidType.SequentialAtEnd, count);
  97. }
  98. /// <summary>
  99. /// Create a sery sequential GUIDs.
  100. /// </summary>
  101. /// <param name="guidType">Type of the GUID.</param>
  102. /// <param name="count">The count.</param>
  103. /// <returns></returns>
  104. public static Guid[] NewSequentialGuid(SequentialGuidType guidType, int count)
  105. {
  106. byte[] randomBytes = new byte[10];
  107. _rng.GetBytes(randomBytes);
  108. UInt32 sequentialID = BitConverter.ToUInt32(randomBytes, 6);
  109. long timestamp = DateTime.UtcNow.Ticks / 10000L;
  110. byte[] timestampBytes = null;
  111. int increment = -1;
  112. Guid[] listGuids = new Guid[count];
  113. byte[] guidBytes = new byte[16];
  114. timestampBytes = BitConverter.GetBytes(timestamp);
  115. switch (guidType)
  116. {
  117. case SequentialGuidType.SequentialAsString:
  118. case SequentialGuidType.SequentialAsBinary:
  119. Buffer.BlockCopy(randomBytes, 0, guidBytes, 6, 6); //Get first 6 byte
  120. if (BitConverter.IsLittleEndian)
  121. {
  122. Array.Reverse(timestampBytes);
  123. }
  124. Buffer.BlockCopy(timestampBytes, 2, guidBytes, 0, 6);
  125. // If formatting as a string, we have to reverse the order
  126. // of the Data1 and Data2 blocks on little-endian systems.
  127. if (guidType == SequentialGuidType.SequentialAsString && BitConverter.IsLittleEndian)
  128. {
  129. Array.Reverse(guidBytes, 0, 4);
  130. Array.Reverse(guidBytes, 4, 2);
  131. }
  132. while (increment++ < count)
  133. {
  134. Buffer.BlockCopy(BitConverter.GetBytes(sequentialID++), 0, guidBytes, 12, 4); //Move last rest 4 byte
  135. listGuids[increment] = new Guid(guidBytes);
  136. }
  137. break;
  138. case SequentialGuidType.SequentialAtEnd:
  139. Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 6); //Get first 6 byte
  140. if (BitConverter.IsLittleEndian)
  141. {
  142. Array.Reverse(timestampBytes);
  143. }
  144. Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6);
  145. while (++increment < count)
  146. {
  147. Buffer.BlockCopy(BitConverter.GetBytes(sequentialID++), 0, guidBytes, 6, 4); //Move last rest 4 byte
  148. listGuids[increment] = new Guid(guidBytes);
  149. }
  150. break;
  151. }
  152. return listGuids;
  153. }
  154. }
  155. }