[英]Entity Framework Core Auto Generated guid
有人可以指导我primeryKey
我想要一个表的primeryKey
作为guid
,在插入时有db生成的值。
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
但它给出了error
无法添加实体类型“用户”的种子实体,因为没有为所需的属性“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 将自动生成,您需要在使用HasData
fluent API 时指定它,并且该值必须是常量(不更改),因此您不能使用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"), ... }
);
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
GUID 字段适用于 Entity Framework 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) 那么你的DbContext
OnModelCreating()
方法应该如下:
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" }
);
}
现在创建一个全新的迁移并相应地更新数据库。 希望你的问题能得到解决!
您可以在 Code First 迁移文件中使用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);
}
除了手动更新迁移,您还可以在 OnModelCreating 中实现一个更新,为您将其添加到迁移中,例如
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()");
}
}
}
GUID
由Identity framework
而不是 EF 处理,因此要使用 GUID,您需要执行以下操作
[Key]
public Guid Id { get; set; }
然后在插入表之前准备模型
new User() { Id = Guid.NewGuid(), Email = "Mubeen@gmail.com", Name = "Mubeen", Password = "123123" },
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id").HasMaxLength(36)
.ValueGeneratedOnAdd();
});
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);
}
}
}
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.SetDefaultValuesTableName();
}
如果您只需要在创建和保存新实体时获取自动值,您也可以在构造函数中执行此操作:
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; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.