实体框架自动生成GUID

时间:2014-08-02 11:51:51

标签: 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 EmailMapper()
        {
            ToTable("EmailTemplate");

            HasKey(c => c.Id);
            Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(c => c.Id).IsRequired();
        }
    }

我正在尝试拨打DbContext.SaveChanges(),但收到以下错误:

  

异常详细信息:System.Data.SqlClient.SqlException:无法将值NULL插入列&#39; Id&#39;,table&#39; AutoSendConnection.dbo.EmailTemplates&#39 ;;列不允许空值。 INSERT失败。

我做错了什么?为什么赢得EF自动创建一个独特的GUID?

8 个答案:

答案 0 :(得分:46)

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

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

您也可以删除Mapper类,因为它不再需要。

答案 1 :(得分:13)

如果使用.Net核心,那么这对您有用......

使用流畅的API

baseScore

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Node>().Property(x => x.ID).HasDefaultValueSql("NEWID()");
}

这是一个更全面的Cheat Sheet for entity framework

答案 2 :(得分:4)

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

答案 3 :(得分:3)

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

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

答案 4 :(得分:2)

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

我以前在SSMS中这样做。

答案 5 :(得分:1)

我更喜欢让数据库自动生成id,例如以下架构:

CREATE TABLE [dbo].[MyTable](
    [MyId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Booking_BookingId]  DEFAULT (newsequentialid())
    )

然后在代码第一个映射中,我指定以下内容告诉实体框架数据库将负责在插入时生成值。

Property(a => a.MyId).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

答案 6 :(得分:1)

在此处解决其他问题

这些其他选项似乎都不起作用,我一次又一次地与EF团队在github上质询了这个问题。

https://github.com/aspnet/EntityFramework6/issues/762

...出于某种原因,EF开发团队似乎认为这是“按设计工作”,并反复关闭质疑该“错误”的票证。

EF团队说明

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

当然,这里的问题是,人口稠密的表冒着您采取进一步的业务操作(使用无效密钥)的风险。

就我而言,这可能会中断一些极其复杂的多服务器DTC事务,因此我认为MS的建议是不正确的。

我的答案(实际上有效)

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

EF code first migrations, DB generated guid keys

要引用另一个问题,答案是...

像通常那样将两个属性都放在关键属性上,生成迁移脚本...

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生成我们期望的密钥。

根据经验,出于一致性原因,我会一直应用此更改,这意味着您的迁移一目了然,您将确切地看到数据库生成了哪些密钥。

答案 7 :(得分:-1)

实体框架核心更新

无需使用[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();