Search code examples
c#entity-frameworkguidentity-framework-migrationsnewsequentialid

GUID COMB strategy in EF


Is there any way to implement the Guid COMB identity strategy for objects in the new Entity Framework 4.1 using the CodeFirst design? I thought setting the StoreGeneratedPattern would work, but it still gives me normal GUIDs.


Solution

  • I guess you are using SQL server as your database. This is nice example of inconsistency among different MS tools. SQL server team doesn't recommend using newid() as default value for UNIQUEIDENTIFIER columns and ADO.NET team use it if you specify Guid property as autogenerated in the database. They should use newsequentialid() instead!

    If you want sequential Guids generated by database you must modify generated table and it is really complex because you must find autogenerated default constraint, drop it and create new constraint. This all can be done in custom database initializer. Here you have my sample code:

    class Program
    {
    
        static void Main(string[] args)
        {
            Database.SetInitializer(new CustomInitializer());
            using (var context = new Context())
            {
                context.TestEntities.Add(new TestEntity() { Name = "A" });
                context.TestEntities.Add(new TestEntity() { Name = "B" });
                context.SaveChanges();
            }
        }
    }
    
    public class CustomInitializer : DropCreateDatabaseAlways<Context>
    {
        protected override void Seed(Context context)
        {
            base.Seed(context);
    
            context.Database.ExecuteSqlCommand(@"
                DECLARE @Name VARCHAR(100)
    
                SELECT @Name = O.Name FROM sys.objects AS O
                INNER JOIN sys.tables AS T ON O.parent_object_id = T.object_id
                WHERE O.type_desc LIKE 'DEFAULT_CONSTRAINT' 
                  AND O.Name LIKE 'DF__TestEntities__Id__%'
                  AND T.Name = 'TestEntities'
    
                DECLARE @Sql NVARCHAR(2000) = 'ALTER TABLE TestEntities DROP Constraint ' + @Name
    
                EXEC sp_executesql @Sql
    
                ALTER TABLE TestEntities
                ADD CONSTRAINT IdDef DEFAULT NEWSEQUENTIALID() FOR Id");
        }
    }
    
    public class TestEntity
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }
    
    public class Context : DbContext
    {
        public DbSet<TestEntity> TestEntities { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<TestEntity>()
                .Property(e => e.Id)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        }
    }