@@ -51,34 +51,51 @@ public static CombGuidGenerator Instance
51
51
/// <returns>An Id.</returns>
52
52
public object GenerateId ( object container , object document )
53
53
{
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
+
54
80
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
58
83
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
60
85
// see: The Cost of GUIDs as Primary Keys by Jimmy Nilson
61
86
// at: http://www.informit.com/articles/article.aspx?p=25862&seqNum=7
62
87
63
- var bytes = Guid . NewGuid ( ) . ToByteArray ( ) ;
88
+ var bytes = guid . ToByteArray ( ) ;
89
+
64
90
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 ) ;
66
92
if ( BitConverter . IsLittleEndian )
67
93
{
68
94
Array . Reverse ( bytes , 10 , 2 ) ;
69
95
Array . Reverse ( bytes , 12 , 4 ) ;
70
96
}
71
- return new Guid ( bytes ) ;
72
- }
73
97
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 ) ;
82
99
}
83
100
}
84
101
}
0 commit comments