C# 无法使用带有标识字段的EF Core 3.0将NULL插入SQL数据库

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

编辑/更新: 好啊我在一个新项目中重建了我的整个脚手架。现在我回到了可以成功插入行的地方,但是表单要求我提供OrgId(数据库的标识)。我提交表单时没有输入OrgID,它会在OriId字段上显示“OrgID字段是必需的”消息

以下是生成的内容:

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);
            }