using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace EasyDevCore.Common
{
///
///
///
public enum SequentialGuidType
{
///
/// The sequential as string (sepecific for MySQL, PostgreSQL ...)
///
SequentialAsString,
///
/// The sequential as binary (sepecific for Oracle)
///
SequentialAsBinary,
///
/// The sequential at end (sepecific for Microsoft SQL Server)
///
SequentialAtEnd
}
///
///
///
public static class SequentialGuidGenerator
{
///
/// The _RNG
///
private static readonly System.Security.Cryptography.RandomNumberGenerator _rng = System.Security.Cryptography.RandomNumberGenerator.Create();
///
/// Create a sequential GUID.
///
/// Type of the GUID.
///
public static Guid NewSequentialGuid(SequentialGuidType guidType)
{
return NewSequentialGuid(guidType, 1)[0];
}
///
/// Nexts the sequential unique identifier.
///
/// The unique identifier.
/// Type of the unique identifier.
///
public static Guid NextSequentialGuid(Guid guid, SequentialGuidType guidType)
{
byte[] guidBytes = guid.ToByteArray();
UInt32 nextID = 0;
switch (guidType)
{
case SequentialGuidType.SequentialAsString:
case SequentialGuidType.SequentialAsBinary:
nextID = BitConverter.ToUInt32(guidBytes, 12) + 1;
Buffer.BlockCopy(BitConverter.GetBytes(nextID), 0, guidBytes, 12, 4);
break;
case SequentialGuidType.SequentialAtEnd:
nextID = BitConverter.ToUInt32(guidBytes, 6) + 1;
Buffer.BlockCopy(BitConverter.GetBytes(nextID), 0, guidBytes, 6, 4);
break;
default:
throw new NotSupportedException(guidType.ToString());
}
return new Guid(guidBytes);
}
///
/// Nexts the sequential unique identifier.
///
/// The unique identifier.
///
public static Guid NextSequentialGuid(Guid guid)
{
return NextSequentialGuid(guid, SequentialGuidType.SequentialAtEnd);
}
///
/// Create a sequential GUID (sepecific for Microsoft SQL Server)
/// (SequentialGuidType = SequentialGuidType.SequentialAtEnd).
///
///
public static Guid NewSequentialGuid()
{
return NewSequentialGuid(SequentialGuidType.SequentialAtEnd, 1)[0];
}
///
/// Create a sery sequential GUIDs (sepecific for Microsoft SQL Server)
/// (SequentialGuidType = SequentialGuidType.SequentialAtEnd).
///
/// The count.
///
public static Guid[] NewSequentialGuid(int count)
{
return NewSequentialGuid(SequentialGuidType.SequentialAtEnd, count);
}
///
/// Create a sery sequential GUIDs.
///
/// Type of the GUID.
/// The count.
///
public static Guid[] NewSequentialGuid(SequentialGuidType guidType, int count)
{
byte[] randomBytes = new byte[10];
_rng.GetBytes(randomBytes);
UInt32 sequentialID = BitConverter.ToUInt32(randomBytes, 6);
long timestamp = DateTime.UtcNow.Ticks / 10000L;
byte[] timestampBytes = null;
int increment = -1;
Guid[] listGuids = new Guid[count];
byte[] guidBytes = new byte[16];
timestampBytes = BitConverter.GetBytes(timestamp);
switch (guidType)
{
case SequentialGuidType.SequentialAsString:
case SequentialGuidType.SequentialAsBinary:
Buffer.BlockCopy(randomBytes, 0, guidBytes, 6, 6); //Get first 6 byte
if (BitConverter.IsLittleEndian)
{
Array.Reverse(timestampBytes);
}
Buffer.BlockCopy(timestampBytes, 2, guidBytes, 0, 6);
// If formatting as a string, we have to reverse the order
// of the Data1 and Data2 blocks on little-endian systems.
if (guidType == SequentialGuidType.SequentialAsString && BitConverter.IsLittleEndian)
{
Array.Reverse(guidBytes, 0, 4);
Array.Reverse(guidBytes, 4, 2);
}
while (increment++ < count)
{
Buffer.BlockCopy(BitConverter.GetBytes(sequentialID++), 0, guidBytes, 12, 4); //Move last rest 4 byte
listGuids[increment] = new Guid(guidBytes);
}
break;
case SequentialGuidType.SequentialAtEnd:
Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 6); //Get first 6 byte
if (BitConverter.IsLittleEndian)
{
Array.Reverse(timestampBytes);
}
Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6);
while (++increment < count)
{
Buffer.BlockCopy(BitConverter.GetBytes(sequentialID++), 0, guidBytes, 6, 4); //Move last rest 4 byte
listGuids[increment] = new Guid(guidBytes);
}
break;
}
return listGuids;
}
}
}