如何配置 EF Core 5 以使 MS SQL Server 数据库生成 Guid 密钥

Posted

技术标签:

【中文标题】如何配置 EF Core 5 以使 MS SQL Server 数据库生成 Guid 密钥【英文标题】:How to configure EF Core 5 to make Guid keys generated by MS SQL Server database 【发布时间】:2021-05-13 04:49:56 【问题描述】:

我正在使用带有 SQL Server 的 EF Core 5,并且我有以下简单实体:

public class Person

    public Guid Id  get; set; 
    public string Name  get; set; 

在 DbContext 中添加为:

public DbSet<Person> People  get; set; 

我运行add-migration Person 得到以下生成的迁移代码:

public partial class Person : Migration

    protected override void Up(MigrationBuilder migrationBuilder)
    
        migrationBuilder.CreateTable(
            name: "People",
            columns: table => new
            
                Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                Name = table.Column<string>(type: "nvarchar(max)", nullable: true)
            ,
            constraints: table =>
            
                table.PrimaryKey("PK_People", x => x.Id);
            );
    

    protected override void Down(MigrationBuilder migrationBuilder)
    
        migrationBuilder.DropTable(
            name: "People");
    

然后我运行update-database 在数据库中创建这个Person 表。

  context.People.Add(new Person()  Name = "John" );
  context.SaveChanges();

查看 EF 日志,我看到执行了 SQL 命令:

  Executed DbCommand (21ms) [Parameters=[@p0='115b2a5d-56b7-42c8-2f42-08d8cd03a34e', @p1='John' (Size = 4000)], CommandType='Text', CommandTimeout='30']
  SET NOCOUNT ON;
  INSERT INTO [People] ([Id], [Name])
  VALUES (@p0, @p1);

我注意到 Id 的第一个参数是 @p0='115b2a5d-56b7-42c8-2f42-08d8cd03a34e',所以这意味着 Guid 是由 EF 生成的,而不是由数据库生成的。我希望它由数据库生成。

所以我在Id 属性中添加了以下属性:

public class Person

    [Key]
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id  get; set; 
    public string Name  get; set; 

但是当我创建一个新的迁移时,它给了我空的 Up()Down() 方法,这意味着从 EF 的角度来看,数据库中不应有任何更改。为什么是这样?以及如何让 EF Core 5 创建由数据库自动生成的 Id 主键。

【问题讨论】:

迁移可能不会改变,但是日志中生成的SQL会改变吗? Fluent API 选项适合您吗? ***.com/questions/25094711/… 如果你这样做,使用这些属性,从一开始(擦除数据库并重新开始)它是否默认 NewID()? @DavidG 刚刚查看了日志,并没有改变EF生成的SQL,所以参数@p0还是传给了数据库。 @madoxdev,我刚刚尝试过这样的 Fluent API:“modelBuilder.Entity().Property(x => x.Id).HasDefaultValueSql("NEWID()");"但下次我尝试添加新的Person 我得到SqlException: Cannot insert the value NULL into column 'Id', table 'dbo.People'; column does not allow nulls. UPDATE fails. The statement has been terminated. 【参考方案1】:

我正在阅读 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 行并找到了这个:

Entity Framework Core 不会实施价值生成策略。数据库提供程序在自动生成值的方式上有所不同。有些会为选定的数据类型生成值,例如 Identity、rowversion、GUI​​D。

如果您只想为您的 mssql 数据库生成一个复杂的密钥,那么我建议将 Id 的类型从 guid 更改为字符串

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public string Id  get; set; 

在迁移文件中是这样的:

migrationBuilder.CreateTable(
columns: table => new
            
                Id = table.Column<string>(type: "nvarchar(450)", nullable: false),
                Name = table.Column<string>(type: "nvarchar(max)", nullable: true)
            ,

【讨论】:

以上是关于如何配置 EF Core 5 以使 MS SQL Server 数据库生成 Guid 密钥的主要内容,如果未能解决你的问题,请参考以下文章

为 ASP.NET Core 5.0 - EF Core 5.0 Web App 配置 PostgreSQL 连接字符串以在 MS 或 Linux 云上运行?

如何使用 EF Core 5 执行存储过程 ORACLE?

不同表共享相同字段时如何设计EF Core代码优先数据库

在 EF Core 6.0 中测试表 IsTemporal

如何比较 EF Core 插值查询中的整数列表

5.EF Core 数据库映射模型隐藏属性配置