实体框架核心自动生成的 GUID



有人可以指导我,我希望primeryKey一个表格,guid在插入时具有数据库生成的值。

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

但它给了error

无法添加实体类型"User"的种子实体,因为没有为所需的属性"Id"提供值。

这是我的实际模型类和 DbContxt 类:

public class BaseModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime? UpdatedOn { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LastAccessed { get; set; }
}
public class User : BaseModel
{
[Required]
[MinLength(3)]
public string Name { get; set; }
[Required]
[MinLength(3)]
[EmailAddress]
public string Email { get; set; }
[Required]
[MinLength(6)]
public string Password { get; set; }
}

然后在 MyDbContext 中:

public class MyDbContext: DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder mb)
{
base.OnModelCreating(mb);

mb.Entity<User>().HasData(
new User() { Email = "Mubeen@gmail.com", Name = "Mubeen", Password = "123123" },
new User() { Email = "Tahir@gmail.com", Name = "Tahir", Password = "321321" },
new User() { Email = "Cheema@gmail.com", Name = "Cheema", Password = "123321" }
);
}
public DbSet<User> User { get; set; }
}

请帮忙!

您遇到的问题并非特定于自动生成的 Guid。任何自动生成的键值(包括常用自动增量(标识)列)都会发生同样的情况。

它是由特定的数据播种 (HasData) 要求引起的:

这种类型的种子数据由迁移管理,需要在不连接到数据库的情况下生成用于更新数据库中已有数据的脚本。这施加了一些限制:

  • 需要指定主键值,即使它通常由数据库生成。它将用于检测迁移之间的数据更改。
  • 如果以任何方式更改主键,将删除以前设定种子的数据。

请注意第一个项目符号。因此,虽然对于普通 CRUD,您的 PK 将自动生成,但在使用流畅 API 时需要指定它HasData并且该值必须是常量(不变),因此您不能使用Guid.NewGuid().因此,您需要生成多个 Guid,获取它们的字符串表示形式并使用如下所示的内容:

mb.Entity<User>().HasData(
new User() { Id = new Guid("pre generated value 1"), ... },
new User() { Id = new Guid("pre generated value 2"), ... },
new User() { Id = new Guid("pre generated value 3"), ... }
);

GUID 字段上的[DatabaseGenerated(DatabaseGeneratedOption.Identity)]适用于实体框架 6.x,可能还不在 EF Core 中!

所以解决方案是:

1)首先编写你的BaseModel类如下:

public class BaseModel
{
[Key]
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedOn { get; set; }
public DateTime LastAccessed { get; set; }
}

2)那么OnModelCreating()DbContext的方法应如下:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<YourEntity>().Property(x => x.Id).HasDefaultValueSql("NEWID()");
modelBuilder.Entity<User>().HasData(
new User() { Id  = Guid.NewGuid(), Email = "Mubeen@gmail.com", Name = "Mubeen", Password = "123123" },
new User() { Id = Guid.NewGuid(), Email = "Tahir@gmail.com", Name = "Tahir", Password = "321321" },
new User() { Id = Guid.NewGuid(),  Email = "Cheema@gmail.com", Name = "Cheema", Password = "123321" }
);
}

现在创建一个全新的迁移并相应地更新数据库。希望您的问题能得到解决!

除了手动更新迁移,您还可以在 OnModelCreate 中实现更新,将其添加到您的迁移中,例如

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// guid identities
foreach (var entity in modelBuilder.Model.GetEntityTypes()
.Where(t =>
t.ClrType.GetProperties()
.Any(p => p.CustomAttributes.Any(a => a.AttributeType == typeof(DatabaseGeneratedAttribute)))))
{
foreach (var property in entity.ClrType.GetProperties()
.Where(p => p.PropertyType == typeof(Guid) && p.CustomAttributes.Any(a => a.AttributeType == typeof(DatabaseGeneratedAttribute))))
{
modelBuilder
.Entity(entity.ClrType)
.Property(property.Name)
.HasDefaultValueSql("newsequentialid()");
}
}
}  

可以在代码优先迁移文件中使用defaultValueSql: "newid()"

例如;

public override void Up()
{
CreateTable(
"dbo.ExampleTable",
c => new
{
Id = c.Guid(nullable: false, identity: true, defaultValueSql: "newid()"),               
RowGuid = c.Guid(nullable: false, defaultValueSql: "newid()"),
})
.PrimaryKey(t => t.Id);           
}

GUIDIdentity framework而不是EF处理,因此要使用GUID,您需要执行以下操作

[Key]
public Guid Id { get; set; }

然后在插入到表中之前准备模型

new User() { Id = Guid.NewGuid(), Email = "Mubeen@gmail.com", Name = "Mubeen", Password = "123123" },

如果你只需要在创建和保存一个新实体时获取一个自动值,你也可以在构造函数中做到这一点:

public class BaseModel
{
public BaseModel()
{
Id = new Guid();
}
[Key]
public Guid Id { get; set; }
public DateTime CreatedOn { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedOn { get; set; }
public DateTime LastAccessed { get; set; }
}
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id").HasMaxLength(36)
.ValueGeneratedOnAdd();
});
  1. 创建一个易于使用的扩展方法:
namespace Microsoft.EntityFrameworkCore
{
using System;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Reflection;
public static class ModelBuilderExtensions
{
public static void SetDefaultValuesTableName(this ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes().Where(x => x.ClrType.GetCustomAttribute(typeof(TableAttribute)) != null))
{
var entityClass = entity.ClrType;
foreach (var property in entityClass.GetProperties().Where(p => (p.PropertyType == typeof(DateTime) || p.PropertyType == typeof(Guid)) && p.CustomAttributes.Any(a => a.AttributeType == typeof(DatabaseGeneratedAttribute))))
{
var defaultValueSql = "GetDate()";
if (property.PropertyType == typeof(Guid))
{
defaultValueSql = "newsequentialid()";
}
modelBuilder.Entity(entityClass).Property(property.Name).HasDefaultValueSql(defaultValueSql);
}
}
}
}
}
  1. 修改您的 OnModelCreate 方法
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.SetDefaultValuesTableName();
}
  1. 利润

最新更新