@@ -51,34 +51,51 @@ public static CombGuidGenerator Instance
5151 /// <returns>An Id.</returns>
5252 public object GenerateId ( object container , object document )
5353 {
54+ var guid = Guid . NewGuid ( ) ;
55+ var timestamp = DateTime . UtcNow ;
56+ return NewCombGuid ( guid , timestamp ) ;
57+ }
58+
59+ /// <summary>
60+ /// Tests whether an Id is empty.
61+ /// </summary>
62+ /// <param name="id">The Id.</param>
63+ /// <returns>True if the Id is empty.</returns>
64+ public bool IsEmpty ( object id )
65+ {
66+ return id == null || ( Guid ) id == Guid . Empty ;
67+ }
68+
69+ /// <summary>
70+ /// Create a new CombGuid from a given Guid and timestamp.
71+ /// </summary>
72+ /// <param name="guid">The base Guid.</param>
73+ /// <param name="timestamp">The timestamp.</param>
74+ /// <returns>A new CombGuid created by combining the base Guid with the timestamp.</returns>
75+ public Guid NewCombGuid ( Guid guid , DateTime timestamp )
76+ {
77+ // note: Guids generated by CombGuidGenerator are only considered ascending by SQL Server which compares Guids in an unusual way
78+ // to generate Guids considered ascending by MongoDB use the AscendingGuidGenerator
79+
5480 var baseDate = new DateTime ( 1900 , 1 , 1 , 0 , 0 , 0 , DateTimeKind . Utc ) ;
55- var now = DateTime . UtcNow ;
56- var days = ( ushort ) ( now - baseDate ) . TotalDays ;
57- var milliseconds = ( int ) now . TimeOfDay . TotalMilliseconds ;
81+ var days = ( ushort ) ( timestamp - baseDate ) . Days ;
82+ var timeTicks = ( int ) ( timestamp . TimeOfDay . Ticks * 300 / TimeSpan . TicksPerSecond ) ; // convert from .NET resolution to SQL Server resolution
5883
59- // replace last 6 bytes of a new Guid with 2 bytes from days and 4 bytes from milliseconds
84+ // replace last 6 bytes of a new Guid with 2 bytes from days and 4 bytes from time of day
6085 // see: The Cost of GUIDs as Primary Keys by Jimmy Nilson
6186 // at: http://www.informit.com/articles/article.aspx?p=25862&seqNum=7
6287
63- var bytes = Guid . NewGuid ( ) . ToByteArray ( ) ;
88+ var bytes = guid . ToByteArray ( ) ;
89+
6490 Array . Copy ( BitConverter . GetBytes ( days ) , 0 , bytes , 10 , 2 ) ;
65- Array . Copy ( BitConverter . GetBytes ( milliseconds ) , 0 , bytes , 12 , 4 ) ;
91+ Array . Copy ( BitConverter . GetBytes ( timeTicks ) , 0 , bytes , 12 , 4 ) ;
6692 if ( BitConverter . IsLittleEndian )
6793 {
6894 Array . Reverse ( bytes , 10 , 2 ) ;
6995 Array . Reverse ( bytes , 12 , 4 ) ;
7096 }
71- return new Guid ( bytes ) ;
72- }
7397
74- /// <summary>
75- /// Tests whether an Id is empty.
76- /// </summary>
77- /// <param name="id">The Id.</param>
78- /// <returns>True if the Id is empty.</returns>
79- public bool IsEmpty ( object id )
80- {
81- return id == null || ( Guid ) id == Guid . Empty ;
98+ return new Guid ( bytes ) ;
8299 }
83100 }
84101}
0 commit comments