diff --git a/src/Core/Repositories/SqlServer/Repository.cs b/src/Core/Repositories/SqlServer/Repository.cs index 6e1ef5e9cb..62180409e8 100644 --- a/src/Core/Repositories/SqlServer/Repository.cs +++ b/src/Core/Repositories/SqlServer/Repository.cs @@ -10,6 +10,8 @@ namespace Bit.Core.Repositories.SqlServer { public abstract class Repository : IRepository where T : IDataObject where TModel : ITableModel { + private static readonly long _baseDateTicks = new DateTime(1900, 1, 1).Ticks; + public Repository(string connectionString, string schema = null, string table = null) { if(string.IsNullOrWhiteSpace(connectionString)) @@ -55,7 +57,7 @@ namespace Bit.Core.Repositories.SqlServer public virtual async Task CreateAsync(T obj) { - obj.Id = Guid.NewGuid().ToString(); + obj.Id = GenerateComb().ToString(); var tableModel = (TModel)Activator.CreateInstance(typeof(TModel), obj); using(var connection = new SqlConnection(ConnectionString)) @@ -107,5 +109,36 @@ namespace Bit.Core.Repositories.SqlServer commandType: CommandType.StoredProcedure); } } + + /// + /// Generate sequential Guid for Sql Server. + /// ref: https://github.com/nhibernate/nhibernate-core/blob/master/src/NHibernate/Id/GuidCombGenerator.cs + /// + /// A comb Guid. + protected Guid GenerateComb() + { + byte[] guidArray = Guid.NewGuid().ToByteArray(); + + var now = DateTime.UtcNow; + + // Get the days and milliseconds which will be used to build the byte string + var days = new TimeSpan(now.Ticks - _baseDateTicks); + var 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 + var daysArray = BitConverter.GetBytes(days.Days); + var 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); + } } }