Sander.SequentialGuid
1.0.0
dotnet add package Sander.SequentialGuid --version 1.0.0
NuGet\Install-Package Sander.SequentialGuid -Version 1.0.0
<PackageReference Include="Sander.SequentialGuid" Version="1.0.0" />
paket add Sander.SequentialGuid --version 1.0.0
#r "nuget: Sander.SequentialGuid, 1.0.0"
// Install Sander.SequentialGuid as a Cake Addin #addin nuget:?package=Sander.SequentialGuid&version=1.0.0 // Install Sander.SequentialGuid as a Cake Tool #tool nuget:?package=Sander.SequentialGuid&version=1.0.0
Introduction
By default, GUIDs are not alphanumerically continuous or sortable in a meaningful way.
A very common use for GUID is a primary key in the database - but with non-sequential GUIDs, it is not optimal to have the primary key as a clustered index. Using clustered index with nonsequential GUIDs can cause fragmentation and general performance issues.
To resolve this, SQL Server has NEWSEQUENTIALID, which creates alphanumerically sortable, sequential GUIDs. The downside ot this approach is that the application will have to wait the SQL Server to create the primary key before the entry becomes usable - and of course, there are other database engines that do not have similar functionality.
Windows has a native UuidCreateSequential function, which is not available on other .NET platforms.
SequentialGuid library is implemented as a .NET Standard 2.0 package, allowing creation of sortable GUIDs prior storing data in the database on any compatible platform. In addition, there are useful helper functions to convert to/from GUID or get specific character/byte.
SequentialGuid is aimed for high-performance applications, as other such libraries are often very underperforming or do not have comparable functionality. SequentialGuid performance is similar to the native UuidCreateSequential, see benchmarks.
Features
- Flexible - define the starting GUID and step, or use the default values
- Fast and memory-efficient - even on a laptop, SequentialGuid handles well over 25 million calls per second. This is comparable or better than the UuidCreateSequential performance
- Thread-safe - create a single SequentialGuid instance for your web application and use it to generate sequential IDs
- .NET Standard 2.0
- Useful helper and extension methods, see below.
Using SequentialGuid
Create one instance of SequentialGuid per sequence (most likely per database table), sharing the instance among all the components which need that. SequentialGuid is fully thread-safe.
public EntityUpdater()
{
...
var lastId = _myDatabaseProvider.GetLastId(); //get last primary key value (GUID) from the database
_sequentialGuid = new SequentialGuid(lastId, 32); //initialize SequentialGuid with lastId as base value and step 32
Trace.WriteLine(_sequentialGuid.Original); //trace the value that we used
}
public async Task<Guid> InsertEntity(ParentObject parent, ChildObject child)
{
var nextId = _sequentialGuid.Next(); //get next sequential GUID, i.e. last + 32
parent.Id = nextId; //set the primary key for DB
//set up the child-parent relation without having to insert parent object first and wait for the result
child.ParentId = nextId;
var task1 = _myDatabaseProvider.InsertAsync(parent);
var task2 = _otherDatabaseProvider.InsertChildAsync(child);
await Task.WhenAll(task1, task2); //wait for both insertions to complete
return nextId;
}
See SequentialGuidTests.cs for more examples.
Extension methods
Extension methods are implemented in class GuidExtensions.
GetCharacterAt(int position)
- get a hexadecimal character at the specified position in GUID (0..31). As this does not rely on GUID being cast to string, it is much faster and uses less memory than default option - see the benchmark.GetByteAt(int position)
- get byte at the specified position (0..15). Somewhat faster thanToByteArray()[position]
, and uses ~30x less memory, see the benchmark. Note that this uses "Microsoft" byte order (see next method), to be compliant with ToByteArray() output.ToCompliantByteArray()
- .NET and Microsoft use different byte order inside GUID structure than other platforms (Java, Python and more). This returns byte array in the same order as Java/Python, and is suitable to be put to the data stores without native GUID/UUID implementation. UseGuidHelper.FromCompliantByteArray()
to reverse the operation, as thenew Guid(byte[] b)
constructor expects ToByteArray()/Microsoft byte order.ToBigInteger(bool isCompliant)
- convert GUID to BigInteger. isCompliant = true is the default, and uses the same approach as ToCompliantByteArray() above, creating integer compatible with other systems and websites (e.g. http://guid-convert.appspot.com).ToLongs()
- convert GUID to (long, long) C# 7 tuple. Generally this should not be needed, but some Javascript libraries have used two integers to represent GUID, which doesn't exist as a native data type in JS.
Helper methods
Helper methods are in static class GuidHelper.
MaxValue
- opposite ofGuid.Empty
, returns the maximum GUID value (ffffffff-ffff-ffff-ffff-ffffffffffff). Useful mainly for testing.FromBigInteger(BigInteger integer, bool isCompliant)
- creates GUID from BigInteger. If the BigInteger is too large (over 16 bytes), excess bytes are trimmed. Defaults to isCompliant = true, using Java/Python-compliant byte ordering.FromDecimal(decimal dec)
- create GUID from .NET decimal numberFromLongs(long first, long second)
- create GUID from two Int64/long numbers. Generally this should not be needed, but some Javascript libraries have used two integers to represent GUID, which doesn't exist as a native data type in JS.FromCompliantByteArray(byte[] bytes)
- seeToCompliantByteArray()
above.
Dependencies
- System.Runtime.Numerics 4.3.0
- System.ValueTuple 4.5.0
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Runtime.Numerics (>= 4.3.0)
- System.ValueTuple (>= 4.5.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 12,976 | 3/15/2019 |