├── .gitattributes ├── .gitignore ├── README.md ├── SequentialGuid.Demo ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── SequentialGuid.Demo.csproj ├── SequentialGuidDemoForm.Designer.cs ├── SequentialGuidDemoForm.cs └── SequentialGuidDemoForm.resx ├── SequentialGuid.sln └── SequentialGuid ├── Classes └── SequentialGuid.cs ├── Enums └── SequentialGuidType.cs ├── Properties └── AssemblyInfo.cs └── SequentialGuid.csproj /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour to automatically normalize line endings. 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | 11 | [Dd]ebug/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | [Bb]in/ 16 | [Oo]bj/ 17 | 18 | # MSTest test Results 19 | [Tt]est[Rr]esult*/ 20 | [Bb]uild[Ll]og.* 21 | 22 | *_i.c 23 | *_p.c 24 | *.ilk 25 | *.meta 26 | *.obj 27 | *.pch 28 | *.pdb 29 | *.pgc 30 | *.pgd 31 | *.rsp 32 | *.sbr 33 | *.tlb 34 | *.tli 35 | *.tlh 36 | *.tmp 37 | *.tmp_proj 38 | *.log 39 | *.vspscc 40 | *.vssscc 41 | .builds 42 | *.pidb 43 | *.log 44 | *.scc 45 | 46 | # Visual C++ cache files 47 | ipch/ 48 | *.aps 49 | *.ncb 50 | *.opensdf 51 | *.sdf 52 | *.cachefile 53 | 54 | # Visual Studio profiler 55 | *.psess 56 | *.vsp 57 | *.vspx 58 | 59 | # Guidance Automation Toolkit 60 | *.gpState 61 | 62 | # ReSharper is a .NET coding add-in 63 | _ReSharper*/ 64 | *.[Rr]e[Ss]harper 65 | 66 | # TeamCity is a build add-in 67 | _TeamCity* 68 | 69 | # DotCover is a Code Coverage Tool 70 | *.dotCover 71 | 72 | # NCrunch 73 | *.ncrunch* 74 | .*crunch*.local.xml 75 | 76 | # Installshield output folder 77 | [Ee]xpress/ 78 | 79 | # DocProject is a documentation generator add-in 80 | DocProject/buildhelp/ 81 | DocProject/Help/*.HxT 82 | DocProject/Help/*.HxC 83 | DocProject/Help/*.hhc 84 | DocProject/Help/*.hhk 85 | DocProject/Help/*.hhp 86 | DocProject/Help/Html2 87 | DocProject/Help/html 88 | 89 | # Click-Once directory 90 | publish/ 91 | 92 | # Publish Web Output 93 | *.Publish.xml 94 | *.pubxml 95 | 96 | # NuGet Packages Directory 97 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 98 | #packages/ 99 | 100 | # Windows Azure Build Output 101 | csx 102 | *.build.csdef 103 | 104 | # Windows Store app package directory 105 | AppPackages/ 106 | 107 | # Others 108 | sql/ 109 | *.Cache 110 | ClientBin/ 111 | [Ss]tyle[Cc]op.* 112 | ~$* 113 | *~ 114 | *.dbmdl 115 | *.[Pp]ublish.xml 116 | *.pfx 117 | *.publishsettings 118 | 119 | # RIA/Silverlight projects 120 | Generated_Code/ 121 | 122 | # Backup & report files from converting an old project file to a newer 123 | # Visual Studio version. Backup files are not needed, because we have git ;-) 124 | _UpgradeReport_Files/ 125 | Backup*/ 126 | UpgradeLog*.XML 127 | UpgradeLog*.htm 128 | 129 | # SQL Server files 130 | App_Data/*.mdf 131 | App_Data/*.ldf 132 | 133 | 134 | #LightSwitch generated files 135 | GeneratedArtifacts/ 136 | _Pvt_Extensions/ 137 | ModelManifest.xml 138 | 139 | # ========================= 140 | # Windows detritus 141 | # ========================= 142 | 143 | # Windows image file caches 144 | Thumbs.db 145 | ehthumbs.db 146 | 147 | # Folder config file 148 | Desktop.ini 149 | 150 | # Recycle Bin used on file shares 151 | $RECYCLE.BIN/ 152 | 153 | # Mac desktop service store files 154 | .DS_Store 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SequentialGuid 2 | ============== 3 | 4 | Author: Jeremy H. Todd (http://jeremytodd.org/) 5 | License: Public domain 6 | 7 | Description 8 | ----------- 9 | 10 | This is an example project to demonstrate the creation of sequential GUID values for use as primary keys in database tables under various database types. 11 | It is intended to accompany my article [GUIDs as fast primary keys under multiple databases](http://www.codeproject.com/Articles/388157/GUIDs-as-fast-primary-keys-under-multiple-database). 12 | 13 | Contents 14 | -------- 15 | 16 | A Visual Studio solution containing two projects: 17 | 18 | * SequentialGuid - A small library containing the types and methods to generate sequential GUIDs using the method outlined in the article. 19 | * SequentialGuid.Demo - A WinForms application demonstrating the generation and use of sequential GUIDs. 20 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | namespace SequentialGuid.Demo 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Windows.Forms; 12 | 13 | /// 14 | /// The entry point of the application. 15 | /// 16 | public static class Program 17 | { 18 | /// 19 | /// The main entry point for the application. 20 | /// 21 | [STAThread] 22 | public static void Main() 23 | { 24 | Application.EnableVisualStyles(); 25 | Application.SetCompatibleTextRenderingDefault(false); 26 | Application.Run(new SequentialGuidDemoForm()); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | using System.Reflection; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices; 9 | 10 | // General Information about an assembly is controlled through the following 11 | // set of attributes. Change these attribute values to modify the information 12 | // associated with an assembly. 13 | [assembly: AssemblyTitle("SequentialGuid.Demo")] 14 | [assembly: AssemblyDescription("A demonstration form for sequential GUIDs.")] 15 | [assembly: AssemblyConfiguration("")] 16 | [assembly: AssemblyCompany("Jeremy H. Todd")] 17 | [assembly: AssemblyProduct("SequentialGuid.Demo")] 18 | [assembly: AssemblyCopyright("Copyright © Jeremy H. Todd 2012")] 19 | [assembly: AssemblyTrademark("")] 20 | [assembly: AssemblyCulture("")] 21 | 22 | // Setting ComVisible to false makes the types in this assembly not visible 23 | // to COM components. If you need to access a type in this assembly from 24 | // COM, set the ComVisible attribute to true on that type. 25 | [assembly: ComVisible(false)] 26 | 27 | // The following GUID is for the ID of the typelib if this project is exposed to COM 28 | [assembly: Guid("6f6df617-95c1-44eb-b59d-14527f2e85e9")] 29 | 30 | // Version information for an assembly consists of the following four values: 31 | // 32 | // Major Version 33 | // Minor Version 34 | // Build Number 35 | // Revision 36 | // 37 | // You can specify all the values or you can default the Build and Revision Numbers 38 | // by using the '*' as shown below: 39 | // [assembly: AssemblyVersion("1.0.*")] 40 | [assembly: AssemblyVersion("1.0.0.0")] 41 | [assembly: AssemblyFileVersion("1.0.0.0")] 42 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18034 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SequentialGuid.Demo.Properties { 12 | 13 | 14 | /// 15 | /// A strongly-typed resource class, for looking up localized strings, etc. 16 | /// 17 | // This class was auto-generated by the StronglyTypedResourceBuilder 18 | // class via a tool like ResGen or Visual Studio. 19 | // To add or remove a member, edit your .ResX file then rerun ResGen 20 | // with the /str option, or rebuild your VS project. 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resources { 25 | 26 | private static global::System.Resources.ResourceManager resourceMan; 27 | 28 | private static global::System.Globalization.CultureInfo resourceCulture; 29 | 30 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 31 | internal Resources() { 32 | } 33 | 34 | /// 35 | /// Returns the cached ResourceManager instance used by this class. 36 | /// 37 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 38 | internal static global::System.Resources.ResourceManager ResourceManager { 39 | get { 40 | if ((resourceMan == null)) { 41 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SequentialGuid.Demo.Properties.Resources", typeof(Resources).Assembly); 42 | resourceMan = temp; 43 | } 44 | return resourceMan; 45 | } 46 | } 47 | 48 | /// 49 | /// Overrides the current thread's CurrentUICulture property for all 50 | /// resource lookups using this strongly typed resource class. 51 | /// 52 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 53 | internal static global::System.Globalization.CultureInfo Culture { 54 | get { 55 | return resourceCulture; 56 | } 57 | set { 58 | resourceCulture = value; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18034 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace SequentialGuid.Demo.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings) (global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/SequentialGuid.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C9B2DD84-3303-47CE-9F7A-85AE7C7699D9} 8 | WinExe 9 | Properties 10 | SequentialGuid.Demo 11 | SequentialGuid.Demo 12 | v4.0 13 | 512 14 | 1 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | True 26 | False 27 | False 28 | False 29 | False 30 | False 31 | True 32 | True 33 | True 34 | True 35 | True 36 | True 37 | True 38 | True 39 | True 40 | True 41 | True 42 | True 43 | True 44 | True 45 | True 46 | False 47 | False 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | True 56 | False 57 | Full 58 | DoNotBuild 59 | 2 60 | 61 | 62 | AnyCPU 63 | pdbonly 64 | true 65 | bin\Release\ 66 | TRACE 67 | prompt 68 | 4 69 | True 70 | True 71 | True 72 | False 73 | False 74 | False 75 | True 76 | True 77 | False 78 | False 79 | False 80 | True 81 | True 82 | False 83 | False 84 | False 85 | True 86 | False 87 | False 88 | True 89 | True 90 | False 91 | True 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | True 100 | False 101 | Preconditions 102 | Build 103 | 0 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Form 113 | 114 | 115 | SequentialGuidDemoForm.cs 116 | 117 | 118 | 119 | 120 | SequentialGuidDemoForm.cs 121 | 122 | 123 | ResXFileCodeGenerator 124 | Resources.Designer.cs 125 | Designer 126 | 127 | 128 | True 129 | Resources.resx 130 | 131 | 132 | SettingsSingleFileGenerator 133 | Settings.Designer.cs 134 | 135 | 136 | True 137 | Settings.settings 138 | True 139 | 140 | 141 | 142 | 143 | {52ee6d7a-286d-44d1-b189-f1f027808e61} 144 | SequentialGuid 145 | 146 | 147 | 148 | 155 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/SequentialGuidDemoForm.Designer.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | namespace SequentialGuid.Demo 7 | { 8 | /// 9 | /// The demonstration form for sequential GUIDs. 10 | /// 11 | public partial class SequentialGuidDemoForm 12 | { 13 | /// 14 | /// Required designer variable. 15 | /// 16 | private System.ComponentModel.IContainer components = null; 17 | 18 | /// The TextBox that contains the results of the GUID generation. 19 | private System.Windows.Forms.RichTextBox resultsTextBox; 20 | 21 | /// The button that begins GUID generation. 22 | private System.Windows.Forms.Button generateButton; 23 | 24 | /// The ComboBox specifying the GUID generation method. 25 | private System.Windows.Forms.ComboBox methodComboBox; 26 | 27 | /// The TextBox that contains the comments. 28 | private System.Windows.Forms.TextBox commentsTextBox; 29 | 30 | /// The label for the method ComboBox. 31 | private System.Windows.Forms.Label methodLabel; 32 | 33 | /// 34 | /// Clean up any resources being used. 35 | /// 36 | /// true if managed resources should be disposed; otherwise, false. 37 | protected override void Dispose(bool disposing) 38 | { 39 | if (disposing && (this.components != null)) 40 | { 41 | this.components.Dispose(); 42 | } 43 | 44 | base.Dispose(disposing); 45 | } 46 | 47 | #region Windows Form Designer generated code 48 | 49 | /// 50 | /// Required method for Designer support - do not modify 51 | /// the contents of this method with the code editor. 52 | /// 53 | private void InitializeComponent() 54 | { 55 | this.resultsTextBox = new System.Windows.Forms.RichTextBox(); 56 | this.generateButton = new System.Windows.Forms.Button(); 57 | this.methodComboBox = new System.Windows.Forms.ComboBox(); 58 | this.commentsTextBox = new System.Windows.Forms.TextBox(); 59 | this.methodLabel = new System.Windows.Forms.Label(); 60 | this.SuspendLayout(); 61 | // 62 | // resultsTextBox 63 | // 64 | this.resultsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 65 | | System.Windows.Forms.AnchorStyles.Left) 66 | | System.Windows.Forms.AnchorStyles.Right))); 67 | this.resultsTextBox.BackColor = System.Drawing.Color.White; 68 | this.resultsTextBox.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 69 | this.resultsTextBox.ForeColor = System.Drawing.Color.Black; 70 | this.resultsTextBox.Location = new System.Drawing.Point(152, 12); 71 | this.resultsTextBox.Name = "resultsTextBox"; 72 | this.resultsTextBox.ReadOnly = true; 73 | this.resultsTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; 74 | this.resultsTextBox.Size = new System.Drawing.Size(546, 297); 75 | this.resultsTextBox.TabIndex = 3; 76 | this.resultsTextBox.Text = string.Empty; 77 | // 78 | // generateButton 79 | // 80 | this.generateButton.Location = new System.Drawing.Point(15, 72); 81 | this.generateButton.Name = "generateButton"; 82 | this.generateButton.Size = new System.Drawing.Size(121, 23); 83 | this.generateButton.TabIndex = 2; 84 | this.generateButton.Text = "Generate"; 85 | this.generateButton.UseVisualStyleBackColor = true; 86 | this.generateButton.Click += new System.EventHandler(this.GenerateButton_Click); 87 | // 88 | // methodComboBox 89 | // 90 | this.methodComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 91 | this.methodComboBox.FormattingEnabled = true; 92 | this.methodComboBox.Location = new System.Drawing.Point(15, 32); 93 | this.methodComboBox.Name = "methodComboBox"; 94 | this.methodComboBox.Size = new System.Drawing.Size(121, 21); 95 | this.methodComboBox.TabIndex = 1; 96 | this.methodComboBox.SelectedIndexChanged += new System.EventHandler(this.MethodComboBox_SelectedIndexChanged); 97 | // 98 | // commentsTextBox 99 | // 100 | this.commentsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 101 | | System.Windows.Forms.AnchorStyles.Right))); 102 | this.commentsTextBox.BackColor = System.Drawing.Color.White; 103 | this.commentsTextBox.ForeColor = System.Drawing.Color.Black; 104 | this.commentsTextBox.Location = new System.Drawing.Point(152, 315); 105 | this.commentsTextBox.Multiline = true; 106 | this.commentsTextBox.Name = "commentsTextBox"; 107 | this.commentsTextBox.ReadOnly = true; 108 | this.commentsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; 109 | this.commentsTextBox.Size = new System.Drawing.Size(546, 120); 110 | this.commentsTextBox.TabIndex = 4; 111 | // 112 | // methodLabel 113 | // 114 | this.methodLabel.AutoSize = true; 115 | this.methodLabel.Location = new System.Drawing.Point(12, 16); 116 | this.methodLabel.Name = "methodLabel"; 117 | this.methodLabel.Size = new System.Drawing.Size(79, 13); 118 | this.methodLabel.TabIndex = 0; 119 | this.methodLabel.Text = "Select Method:"; 120 | // 121 | // SequentialGuidDemoForm 122 | // 123 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 124 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 125 | this.ClientSize = new System.Drawing.Size(710, 447); 126 | this.Controls.Add(this.methodLabel); 127 | this.Controls.Add(this.commentsTextBox); 128 | this.Controls.Add(this.methodComboBox); 129 | this.Controls.Add(this.generateButton); 130 | this.Controls.Add(this.resultsTextBox); 131 | this.Name = "SequentialGuidDemoForm"; 132 | this.Text = "SequentialGuid Demonstration Form"; 133 | this.ResumeLayout(false); 134 | this.PerformLayout(); 135 | } 136 | 137 | #endregion 138 | } 139 | } -------------------------------------------------------------------------------- /SequentialGuid.Demo/SequentialGuidDemoForm.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | namespace SequentialGuid.Demo 7 | { 8 | using System; 9 | using System.Text; 10 | using System.Windows.Forms; 11 | 12 | /// 13 | /// The demonstration form for sequential GUIDs. 14 | /// 15 | public partial class SequentialGuidDemoForm : Form 16 | { 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | public SequentialGuidDemoForm() 21 | { 22 | this.InitializeComponent(); 23 | 24 | // Load the enumeration values into the combo box 25 | foreach (var value in Enum.GetValues(typeof(SequentialGuidType))) 26 | { 27 | this.methodComboBox.Items.Add(value); 28 | } 29 | 30 | this.methodComboBox.SelectedIndex = 0; 31 | } 32 | 33 | /// 34 | /// Updates the form when the user changes the value of the Method ComboBox. 35 | /// 36 | /// The Method ComboBox. 37 | /// Additional information related to the event. 38 | private void MethodComboBox_SelectedIndexChanged(object sender, EventArgs e) 39 | { 40 | string comments = string.Empty; 41 | 42 | switch ((SequentialGuidType)this.methodComboBox.SelectedItem) 43 | { 44 | case SequentialGuidType.SequentialAsBinary: 45 | comments = "GUIDs will be generated using the SequentialAsBinary method, which is appropriate " + 46 | "if the values are going to be written to a binary field, such as a raw(16) column " + 47 | "under Oracle, or a binary(16) column under MySQL. These GUIDs are formatted by " + 48 | "invoking Guid.ToByteArray() on the GUID value, then writing the results to a hex " + 49 | "string. This is most likely the way ORM frameworks would generate INSERT statements " + 50 | "for writing to a binary field. The sequential portion of the generated GUIDs will be " + 51 | "highlighted in red."; 52 | break; 53 | 54 | case SequentialGuidType.SequentialAsString: 55 | comments = "GUIDs will be generated using the SequentialAsString method, which is appropriate " + 56 | "if the values are going to be written to a string-based column (which would include " + 57 | "char(36) columns under MySQL and other database, or a uuid column under PostgreSQL). " + 58 | "These GUIDs are formatted by invoking Guid.ToString() on the GUID value. Why do " + 59 | "string-based columns need a different format from binary columns? Because a quirk " + 60 | "of the way the .NET Framework handles GUIDs introduces endianness issues that need " + 61 | "to be corrected when writing to a string. The sequential portion of the generated " + 62 | "GUIDs will be highlighted in red."; 63 | break; 64 | 65 | case SequentialGuidType.SequentialAtEnd: 66 | comments = "GUIDs will be generated using the SequentialAtEnd method, which is pretty much " + 67 | "only appropriate for a Microsoft SQL Server uniqueidentifier column. This special " + 68 | "format is necessary because SQL Server uses an unusual ordering scheme for GUID " + 69 | "values, basing the order on the last six bytes instead of starting from the beginning." + 70 | "The sequential portion of the generated GUIDs will be highlighted in red."; 71 | break; 72 | } 73 | 74 | this.resultsTextBox.Clear(); 75 | this.commentsTextBox.Text = comments; 76 | } 77 | 78 | /// 79 | /// Generates the GUIDs and displays them in the form. 80 | /// 81 | /// The Generate button. 82 | /// Additional information related to the event. 83 | private void GenerateButton_Click(object sender, EventArgs e) 84 | { 85 | int count = 100; 86 | SequentialGuidType method = (SequentialGuidType)this.methodComboBox.SelectedItem; 87 | 88 | // Initialize the RTF text to enable color highlighting 89 | StringBuilder text = new StringBuilder(); 90 | text.Append("{\\rtf1\\ansi\\deff0\n{\\colortbl;\\red0\\green0\\blue0;\\red128\\green0\\blue0;}\n"); 91 | 92 | for (int i = 0; i < count; i++) 93 | { 94 | Guid guid = SequentialGuid.Create(method); 95 | string output = string.Empty; 96 | 97 | switch (method) 98 | { 99 | case SequentialGuidType.SequentialAsBinary: 100 | byte[] bytes = guid.ToByteArray(); 101 | 102 | foreach (byte b in bytes) 103 | { 104 | output += string.Format("{0:x2}", b); 105 | } 106 | 107 | output = "\\cf2\n" + output.Substring(0, 12) + "\n\\cf1\n" + output.Substring(12) + "\n\\line\n"; 108 | break; 109 | 110 | case SequentialGuidType.SequentialAsString: 111 | output = guid.ToString(); 112 | output = "\\cf2\n" + output.Substring(0, 13) + "\n\\cf1\n" + output.Substring(13) + "\n\\line\n"; 113 | break; 114 | 115 | case SequentialGuidType.SequentialAtEnd: 116 | output = guid.ToString(); 117 | output = "\\cf1\n" + output.Substring(0, 24) + "\n\\cf2\n" + output.Substring(24) + "\n\\line\n"; 118 | break; 119 | 120 | default: 121 | output = guid.ToString(); 122 | break; 123 | } 124 | 125 | text.Append(output); 126 | System.Threading.Thread.Sleep(1); 127 | } 128 | 129 | this.resultsTextBox.Rtf = text.ToString(); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /SequentialGuid.Demo/SequentialGuidDemoForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /SequentialGuid.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SequentialGuid.Demo", "SequentialGuid.Demo\SequentialGuid.Demo.csproj", "{C9B2DD84-3303-47CE-9F7A-85AE7C7699D9}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SequentialGuid", "SequentialGuid\SequentialGuid.csproj", "{52EE6D7A-286D-44D1-B189-F1F027808E61}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {C9B2DD84-3303-47CE-9F7A-85AE7C7699D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {C9B2DD84-3303-47CE-9F7A-85AE7C7699D9}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {C9B2DD84-3303-47CE-9F7A-85AE7C7699D9}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {C9B2DD84-3303-47CE-9F7A-85AE7C7699D9}.Release|Any CPU.Build.0 = Release|Any CPU 18 | {52EE6D7A-286D-44D1-B189-F1F027808E61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {52EE6D7A-286D-44D1-B189-F1F027808E61}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {52EE6D7A-286D-44D1-B189-F1F027808E61}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {52EE6D7A-286D-44D1-B189-F1F027808E61}.Release|Any CPU.Build.0 = Release|Any CPU 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | EndGlobal 27 | -------------------------------------------------------------------------------- /SequentialGuid/Classes/SequentialGuid.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | namespace SequentialGuid 7 | { 8 | using System; 9 | using System.Diagnostics.Contracts; 10 | using System.Security.Cryptography; 11 | 12 | /// 13 | /// Contains methods for creating sequential GUID values. 14 | /// 15 | public static partial class SequentialGuid 16 | { 17 | #region Static Fields 18 | /// 19 | /// Provides cryptographically strong random data for GUID creation. 20 | /// 21 | private static readonly RNGCryptoServiceProvider RandomGenerator = new RNGCryptoServiceProvider(); 22 | #endregion 23 | 24 | /// 25 | /// Returns a new GUID value which is sequentially ordered when formatted as 26 | /// a string, a byte array, or ordered by the least significant six bytes of the 27 | /// Data4 block, as specified by . 28 | /// 29 | /// 30 | /// Specifies the type of sequential GUID (i.e. whether sequential as a string, 31 | /// as a byte array, or according to the Data4 block. This can affect 32 | /// performance under various database types; see below. 33 | /// 34 | /// 35 | /// A structure whose value is created by replacing 36 | /// certain randomly-generated bytes with a sequential timestamp. 37 | /// 38 | /// 39 | /// 40 | /// This method creates a new GUID value which combines a random component 41 | /// with the current timestamp, also known as a COMB. The general concept 42 | /// is outlined in Jimmy Nilsson's article "The Cost of GUIDs as Primary Keys", 43 | /// and involves replacing either the least significant or most significant 44 | /// six bytes of the GUID with the current timestamp. This reduces the 45 | /// random component of the GUID from 16 bytes to 10 bytes, but this is 46 | /// still sufficient to prevent a collision under most real-world circumstances. 47 | /// 48 | /// 49 | /// The purpose of sequential GUIDs is not to promote the use of GUIDs as 50 | /// sortable entities. In fact, GUIDs generated very close together may 51 | /// have the same timestamp and are not guaranteed to be sequentially ordered 52 | /// at all. The intent is to increase performance when doing repeated 53 | /// inserts into database tables that have a clustered index on a GUID 54 | /// column, so that later entries do not have to be inserted into the middle 55 | /// of the table, but can simply be appended to the end. 56 | /// 57 | /// 58 | /// According to experiments, Microsoft SQL Server sorts GUID values using 59 | /// the least significant six bytes of the Data4 block; therefore, GUIDs being 60 | /// generated for use with SQL Server should pass a 61 | /// value of SequentialAtEnd. GUIDs generated for most other database 62 | /// types should be passed a value of 63 | /// SequentialAsString or SequentialAsByteArray. 64 | /// 65 | /// 66 | /// Various standards already define a time-based UUID; however, the 67 | /// format specified by these standards splits the timestamp into 68 | /// several components, limiting its usefulness as a sequential ID. 69 | /// Additionally, the format used for such UUIDs is not compatible 70 | /// with the GUID ordering on Microsoft SQL Server. 71 | /// 72 | /// 73 | public static Guid Create(SequentialGuidType guidType) 74 | { 75 | // We start with 16 bytes of cryptographically strong random data. 76 | byte[] randomBytes = new byte[10]; 77 | SequentialGuid.RandomGenerator.GetBytes(randomBytes); 78 | 79 | // An alternate method: use a normally-created GUID to get our initial 80 | // random data: 81 | // byte[] randomBytes = Guid.NewGuid().ToByteArray(); 82 | // This is faster than using RNGCryptoServiceProvider, but I don't 83 | // recommend it because the .NET Framework makes no guarantee of the 84 | // randomness of GUID data, and future versions (or different 85 | // implementations like Mono) might use a different method. 86 | 87 | // Now we have the random basis for our GUID. Next, we need to 88 | // create the six-byte block which will be our timestamp. 89 | 90 | // We start with the number of milliseconds that have elapsed since 91 | // DateTime.MinValue. This will form the timestamp. There's no use 92 | // being more specific than milliseconds, since DateTime.Now has 93 | // limited resolution. 94 | 95 | // Using millisecond resolution for our 48-bit timestamp gives us 96 | // about 5900 years before the timestamp overflows and cycles. 97 | // Hopefully this should be sufficient for most purposes. :) 98 | long timestamp = DateTime.UtcNow.Ticks / 10000L; 99 | 100 | // Then get the bytes 101 | byte[] timestampBytes = BitConverter.GetBytes(timestamp); 102 | 103 | // Since we're converting from an Int64, we have to reverse on 104 | // little-endian systems. 105 | if (BitConverter.IsLittleEndian) 106 | { 107 | Array.Reverse(timestampBytes); 108 | } 109 | 110 | byte[] guidBytes = new byte[16]; 111 | 112 | switch (guidType) 113 | { 114 | case SequentialGuidType.SequentialAsString: 115 | case SequentialGuidType.SequentialAsBinary: 116 | 117 | // For string and byte-array version, we copy the timestamp first, followed 118 | // by the random data. 119 | Buffer.BlockCopy(timestampBytes, 2, guidBytes, 0, 6); 120 | Buffer.BlockCopy(randomBytes, 0, guidBytes, 6, 10); 121 | 122 | // If formatting as a string, we have to compensate for the fact 123 | // that .NET regards the Data1 and Data2 block as an Int32 and an Int16, 124 | // respectively. That means that it switches the order on little-endian 125 | // systems. So again, we have to reverse. 126 | if (guidType == SequentialGuidType.SequentialAsString && BitConverter.IsLittleEndian) 127 | { 128 | Array.Reverse(guidBytes, 0, 4); 129 | Array.Reverse(guidBytes, 4, 2); 130 | } 131 | 132 | break; 133 | 134 | case SequentialGuidType.SequentialAtEnd: 135 | 136 | // For sequential-at-the-end versions, we copy the random data first, 137 | // followed by the timestamp. 138 | Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 10); 139 | Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6); 140 | break; 141 | } 142 | 143 | return new Guid(guidBytes); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /SequentialGuid/Enums/SequentialGuidType.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | namespace SequentialGuid 7 | { 8 | using System; 9 | 10 | /// 11 | /// Describes the type of a sequential GUID value. 12 | /// 13 | public enum SequentialGuidType 14 | { 15 | /// 16 | /// The GUID should be sequential when formatted using the 17 | /// method. 18 | /// 19 | SequentialAsString, 20 | 21 | /// 22 | /// The GUID should be sequential when formatted using the 23 | /// method. 24 | /// 25 | SequentialAsBinary, 26 | 27 | /// 28 | /// The sequential portion of the GUID should be located at the end 29 | /// of the Data4 block. 30 | /// 31 | SequentialAtEnd 32 | } 33 | } -------------------------------------------------------------------------------- /SequentialGuid/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------- 2 | // 3 | // Copyright © Jeremy H. Todd 2011 4 | // 5 | //----------------------------------------------------------------------- 6 | 7 | using System.Reflection; 8 | using System.Runtime.CompilerServices; 9 | using System.Runtime.InteropServices; 10 | 11 | // General Information about an assembly is controlled through the following 12 | // set of attributes. Change these attribute values to modify the information 13 | // associated with an assembly. 14 | [assembly: AssemblyTitle("SequentialGuid")] 15 | [assembly: AssemblyDescription("An example library demonstrating the creation of sequential GUID values suitable for use as high-performance primary keys in various database systems.")] 16 | [assembly: AssemblyConfiguration("")] 17 | [assembly: AssemblyCompany("Jeremy H. Todd")] 18 | [assembly: AssemblyProduct("SequentialGuid")] 19 | [assembly: AssemblyCopyright("Copyright © Jeremy H. Todd 2012")] 20 | [assembly: AssemblyTrademark("")] 21 | [assembly: AssemblyCulture("")] 22 | 23 | // Setting ComVisible to false makes the types in this assembly not visible 24 | // to COM components. If you need to access a type in this assembly from 25 | // COM, set the ComVisible attribute to true on that type. 26 | [assembly: ComVisible(false)] 27 | 28 | // The following GUID is for the ID of the typelib if this project is exposed to COM 29 | [assembly: Guid("d202a529-423c-4ccf-96c9-b4e0d30c17d2")] 30 | 31 | // Version information for an assembly consists of the following four values: 32 | // 33 | // Major Version 34 | // Minor Version 35 | // Build Number 36 | // Revision 37 | // 38 | // You can specify all the values or you can default the Build and Revision Numbers 39 | // by using the '*' as shown below: 40 | // [assembly: AssemblyVersion("1.0.*")] 41 | [assembly: AssemblyVersion("1.0.0.0")] 42 | [assembly: AssemblyFileVersion("1.0.0.0")] 43 | -------------------------------------------------------------------------------- /SequentialGuid/SequentialGuid.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {52EE6D7A-286D-44D1-B189-F1F027808E61} 8 | Library 9 | Properties 10 | SequentialGuid 11 | SequentialGuid 12 | v4.0 13 | 512 14 | 15 | 1 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | True 26 | False 27 | False 28 | False 29 | False 30 | True 31 | True 32 | True 33 | True 34 | True 35 | True 36 | True 37 | True 38 | True 39 | True 40 | True 41 | True 42 | True 43 | True 44 | True 45 | False 46 | False 47 | 48 | 49 | 50 | 51 | 52 | 53 | True 54 | Full 55 | Build 56 | 2 57 | 58 | 59 | pdbonly 60 | true 61 | bin\Release\ 62 | TRACE 63 | prompt 64 | 4 65 | True 66 | True 67 | True 68 | False 69 | False 70 | False 71 | False 72 | False 73 | False 74 | False 75 | False 76 | False 77 | False 78 | False 79 | False 80 | True 81 | False 82 | False 83 | True 84 | True 85 | False 86 | True 87 | 88 | 89 | 90 | 91 | 92 | 93 | True 94 | Preconditions 95 | Build 96 | 0 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 115 | --------------------------------------------------------------------------------