C# 实体框架自动生成GUID

C# 实体框架自动生成GUID,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我是EF的新手,我有一个包含以下内容的类 public class EmailTemplate { public Guid Id { get; set; } [MaxLength(2000)] public string Html { get; set; } } 这是我的映射类 class EmailMapper : EntityTypeConfiguration<EmailTemplate> { public EmailMappe

我是EF的新手,我有一个包含以下内容的类

public class EmailTemplate
{
    public Guid Id { get; set; }

    [MaxLength(2000)]
    public string Html { get; set; }
}
这是我的映射类

class EmailMapper : EntityTypeConfiguration<EmailTemplate>
    {
        public EmailMapper()
        {
            ToTable("EmailTemplate");

            HasKey(c => c.Id);
            Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(c => c.Id).IsRequired();
        }
    }
class EmailMapper:EntityTypeConfiguration
{
公共EmailMapper()
{
ToTable(“电子邮件模板”);
HasKey(c=>c.Id);
属性(c=>c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
属性(c=>c.Id).IsRequired();
}
}
我试图调用
DbContext.SaveChanges()
,但出现以下错误:

异常详细信息:System.Data.SqlClient.SqlException:无法将值NULL插入到“Id”列、表“AutoSendConnection.dbo.EmailTemplates”中;列不允许空值。插入失败


我做错了什么?为什么EF不会自动创建唯一的GUID?

在映射配置中将字段的默认sql值设置为“newsequentialid()”

您还可以在Sql Server本身中将ID的默认值设置为NewID(),并将GUID传递为null


我曾经在SSMS中这样做。

只需在EmailTemplate类中修饰Id字段,如下所示,SQL Server将在插入时自动生成值

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
Property(a => a.MyId).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

您还可以删除不再需要的Mapper类。

如果使用.Net core,那么这应该适合您

使用fluentapi

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Node>().Property(x => x.ID).HasDefaultValueSql("NEWID()");
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().Property(x=>x.ID).HasDefaultValueSql(“NEWID()”);
}

modelBuilder.Entity().Property(p=>p.StudentID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

下面是一个更全面的

实体框架核心更新:

无需使用
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

无需使用
fluent API

EF Core会自动处理它,并为主键生成Id

例如:

public class DummyEntity
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

}
播种

    _context.DummyEntities.Add(new DummyEntity
    {
        FirstName = "Abc",
        LastName = "Def",
        Postion = "User",
    });

    _context.SaveChanges();

我更喜欢离开数据库自动生成id,例如以下模式:

CREATE TABLE [dbo].[MyTable](
    [MyId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Booking_BookingId]  DEFAULT (newsequentialid())
    )
然后,在代码优先映射中,我指定以下内容来告诉实体框架,数据库将负责生成insert上的值

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
Property(a => a.MyId).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

在此回答其他问题

这些其他选项似乎都不起作用,我在github上与EF团队一次又一次地对此提出质疑

。。。出于某种原因,EF开发团队似乎认为这是“按设计进行的”,并反复关闭质疑这一“错误”的罚单

英孚团队解释

出于某种原因,他们似乎认为“在SQL中生成GUI被认为不是最佳实践,为了确保密钥立即可用,我们应该在应用程序代码中生成密钥”

当然,这里的问题是,高度填充的表可能会导致您使用无效密钥执行进一步的业务操作

在我的案例中,这可能会破坏一些极其复杂的多服务器DTC事务,因此我不相信MS的建议是正确的,即EF Core目前根本不支持分布式事务,因此在重点关注的上下文中,它们可能有道理

我的答案(实际有效)

简言之,我通过在生成迁移后“手动破解”生成的迁移来解决这个问题

引用另一个问题,答案如下:

生成迁移脚本,就像您通常将两个属性放在key属性上一样,如下所示

public class Foo
{
     [Key]
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     public Guid Id { get; set; }
}
。。。声明性地说,实体现在是正确的

它将生成的迁移类似于:

CreateTable(
    "dbo.Foos",
    c => new
        {
            Id = c.Guid(nullable: false),
            ...
        })
    .PrimaryKey(t => t.Id)
    ...;
。。。我还没有弄清楚原因,但在某些情况下这会起作用,而在其他情况下则不会(运行迁移,执行插入测试)

如果失败,请回滚迁移,然后将其修改为

CreateTable(
    "dbo.Foos",
    c => new
        {
            Id = c.Guid(nullable: false, defaultValueSql: "newid()"),
            ...
        })
    .PrimaryKey(t => t.Id)
    ...;
。。。这里的额外代码告诉SQL按照我们的预期生成密钥


根据经验,出于一致性原因,我会一直应用此更改,这意味着您的迁移将一目了然地显示db生成了哪些键,当然哪些键没有生成。

经过长时间的调查,我发现在EF Core 3.1中,您需要使用

builder.Property(e => e.Id).ValueGeneratedOnAdd();

顺序ID会减少索引的碎片,从而提高查询性能即使在SQL server中将ID的默认值设置为NewID(),如果尚未设置StoreGeneratedPattern属性,仍需要修改.edmx文件。ref:@ChinhPhan在标准情况下,我认为我们不需要更改任何XML。我使用向导创建EDMX文件,一切正常。请在修改后的问题中查看我的映射类,我将newsequentialid()放在哪里?我试图先通过代码来实现这一点,我只是认为EF会处理它?这显示了一个例子:实际上,这与OP在他们的代码中已经做的是一样的。虽然这是一个解决问题的方法,但它不能解决原始问题。如果使用CodeFirst,EF可能检测不到此更改。您可以删除表并添加新迁移。生成的迁移中未设置默认sql值,因此此操作不起作用(即使从头创建表时也是如此)。此答案仅适用于EF Core。。。EF6用户会发现这有问题。这在EF Core中不起作用。迁移文件没有此Id列的任何标识信息。在EntityFrameworkCore 1.0.4上,这还不够。我必须使用entity.Property(e=>e.Id).ValueGeneratedOnAdd();这对我起了作用。投了反对票,因为这似乎不准确。生成迁移时,默认值设置为新Guid(“00000000-0000-0000-0000-0000-000000000000”)。请更新您的答案。您是对的,ef core会处理它,但它不会构建一个数据库表来正确地处理自动生成guid的问题,例如在SQL server中