9

有没有办法使用 CodeFirst 设计为新实体框架 4.1 中的对象实现 Guid COMB 标识策略?我认为设置StoreGeneratedPattern会起作用,但它仍然给了我正常的 GUID。

4

3 回答 3

18

为什么要担心数据库中 Guid 列的默认值?为什么不像其他值一样在客户端生成 Guid。这要求您在客户端代码中有一个方法,该方法将生成类似 COMB 的 guid:

public static Guid NewGuid()
{
    var guidBinary = new byte[16];
    Array.Copy( Guid.NewGuid().ToByteArray(), 0, guidBinary, 0, 8 );
    Array.Copy( BitConverter.GetBytes( DateTime.Now.Ticks ), 0, guidBinary, 8, 8 );
    return new Guid( guidBinary );
}

Guid 的优点之一是您可以在客户端上生成它们,而无需往返数据库。

于 2011-05-23T17:36:59.283 回答
9

我猜你正在使用 SQL 服务器作为你的数据库。这是不同 MS 工具之间不一致的一个很好的例子。SQL Server 团队不建议将列newid()用作默认值,UNIQUEIDENTIFIER如果您将Guid属性指定为在数据库中自动生成,ADO.NET 团队会使用它。他们应该newsequentialid()改用!

如果你想要由数据库生成的顺序 Guid,你必须修改生成的表,这真的很复杂,因为你必须找到自动生成的默认约束,删除它并创建新的约束。这一切都可以在自定义数据库初始化程序中完成。这里有我的示例代码:

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);
    }
}
于 2011-05-23T17:20:38.520 回答
2

最简单的答案

public class User
{
    public User(Guid? id = null, DateTime? created = null)
    {
        if (id != null)
            Id = id;

        if (created != null)
            Created = created;
    }

    public User()
    {
    }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime? Created { get; internal set; }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid? Id { get; internal set; }
}

这假设您已将数据库表设置为默认值newsequentialid(),在我的情况下,该表由 FluentMigrator 迁移管理。

于 2011-08-17T20:10:33.307 回答