C# 无法使用带有标识字段的EF Core 3.0将NULL插入SQL数据库
编辑/更新: 好啊我在一个新项目中重建了我的整个脚手架。现在我回到了可以成功插入行的地方,但是表单要求我提供OrgId(数据库的标识)。我提交表单时没有输入OrgID,它会在OriId字段上显示“OrgID字段是必需的”消息 以下是生成的内容:C# 无法使用带有标识字段的EF Core 3.0将NULL插入SQL数据库,c#,asp.net-core,entity-framework-core,data-annotations,C#,Asp.net Core,Entity Framework Core,Data Annotations,编辑/更新: 好啊我在一个新项目中重建了我的整个脚手架。现在我回到了可以成功插入行的地方,但是表单要求我提供OrgId(数据库的标识)。我提交表单时没有输入OrgID,它会在OriId字段上显示“OrgID字段是必需的”消息 以下是生成的内容: entity.Property(e=>e.OrgId) .HasColumnName(“OrgID”) .ValueGeneratedNever() 及 public intorgid{get;set;} 我尝试添加数据注释,将其标记为主键(但我认为在F
entity.Property(e=>e.OrgId)
.HasColumnName(“OrgID”)
.ValueGeneratedNever()代码>
及
public intorgid{get;set;}
我尝试添加数据注释,将其标记为主键(但我认为在Fluent中已经出现了这种情况):
[Key]
[数据库生成(DatabaseGeneratedOption.Identity)]
我知道一定有办法使表格不需要身份证明。它应该让数据库来解决这个问题
这让我发疯,因为它看起来应该如此简单。我有一个数据库,当用户不提供自己的默认值时,它有自己的默认值。例如,我有一个标识字段和一个创建日期。这两个我想我的EF代码做什么。数据库为我处理所有这些
我尝试了许多数据注释和上下文属性的变体。似乎没有什么是正确的,这是一些非常基本的东西。我的代码99%是用内置在VisualStudio中的脚手架构建的。除了设法使积垢起作用外,我几乎没有做任何修改
Organizations.cs数据模型
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrgId { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RowCreated { get; set; }
DataContext.cs
entity.HasKey(e => e.OrgId);
entity.Property(e => e.OrgId).HasColumnName("OrgID").UseIdentityColumn();
entity.Property(e => e.RowCreated).HasColumnType("datetime").HasDefaultValueSql("GETUTCDATE()");
我这里有几个问题
数据库回复我说它不能接受标识列OrgID的NULL,那么为什么EF Core在中发送NULL值呢
为什么在提交时创建页面需要创建行
我的理解是,设置这些数据注释是为了告诉EF Core数据库将处理这些注释,并忽略它们
我更改了RowCreated的模型定义,但感觉它不是合适的解决方案:
public DateTime? RowCreated
{
get
{
return _rowCreated;
}
set
{
_rowCreated = DateTime.UtcNow;
}
}
其实很简单。
首先,您有OrgId,它是表中的主键,但您不需要一些随机值,因为您有一个预定义的值(据我所知)。
您的第一次尝试实际上很好:
public int OrgId { get; set; }
entity.HasKey(e => e.OrgId);
entity.Property(e => e.OrgId)
.HasColumnName("OrgID")
.ValueGeneratedNever();
因为您在这里使用了ValueGeneratedNever选项,所以每次在此表中插入值时都需要为OrgId提供值。如果您想在创建迁移时为数据设定种子,您有很多方法可以做到这一点,而且,您需要提供OrgId值
当您想要设置创建日期时,可以通过以下方式进行设置:
已创建公共日期时间行{get;set;}
及
我在DbContext中做的另一件事是重写SaveChangesSync方法,以便忽略对CreatedDate(您的行已创建)的更新:
public override Task savechangessync(CancellationToken CancellationToken=default)
{
foreach(ChangeTracker.Entries()中的var条目)
{
if(entry.Properties.Where(p=>p.Metadata.Name==“RowCreated”).Count()>0)
entry.Property(“RowCreated”).IsModified=false;
}
返回base.saveChangesSync(cancellationToken);
}
如果您使用的是SaveChanges方法而不是SaveChangesAsync,您只需在此处执行相同的操作。请检查EF核心
有三种可用于属性的值生成模式:
- 没有价值产生
- 增值
- 添加或更新时生成的值
数据库向我反馈说它不能接受NULL
对于标识列OrgID,那么为什么EF Core发送空值呢
在哪
由于您正在使用OrgID属性的ValueGeneratedNever()
方法,因此在将值插入数据库时,需要在插入新实体时提供此属性的值。如果要自动生成值,可以将ValueGeneratedNever()
方法更改为ValueGeneratedOnAdd()
方法
为什么在提交时创建页面需要创建行
您的意思是在“创建”页面中,RowCreated属性是必需的吗?如果是这种情况,请首先检查数据模型和OnModelCreating方法,是否已为RowCreated属性设置所需的验证属性
第二,请检查客户端站点验证,可能需要为RowCreated属性添加客户端验证。尝试修改/删除它。感谢您的回复。非常感谢。然而,表单中仍然需要OrgId。事实上,我想让这个字段在编辑器上成为只读的。任何人都不应该碰这个字段,因为我需要数据库来创建它并离开它。如果我提供OrgId,表单可以正常工作,但我不想在我的场景中提供它。为了进一步澄清,数据库在过去有一个种子值,每次插入新记录时OrgId只加1。感谢您的帮助。事情总的来说是可行的。目前我唯一的问题是网页需要OrgId。我已经尝试了我能想到的所有属性,让表单忽略此字段。数据库控制着这个字段,它需要保持这种状态。根据您的描述和讨论,您的意思是您已经将OrgID属性设置为标识列了吗。它将从数据库自动生成值(+1),因此,在“创建”页面中,不需要提供值。但在“创建”页面中,如果您不提供此值,它将显示“OrgId字段是必需的”错误,对吗?在这个场景中,我建议您检查页面模型,确保它使用正确的模型。此外,您还可以创建一个页面模型来收集创建页面中的实体信息
entity.Property(e => e.RowCreated)
.HasColumnType("datetime")
.HasDefaultValueSql("getutcdate()")
.ValueGeneratedOnAdd()
;
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
foreach (var entry in ChangeTracker.Entries())
{
if (entry.Properties.Where(p => p.Metadata.Name == "RowCreated").Count() > 0)
entry.Property("RowCreated").IsModified = false;
}
return base.SaveChangesAsync(cancellationToken);
}