我是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?
答案 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();