EFCore不能在列中插入NULL值



我接受来自用户的3个字段。所有3个字段都必须输入。查看下面的实体配置—EntityConfiguration中的所有3个字段都被标记为Required

当我将新记录保存到数据库时,这可以完美地工作。但是,现在我需要更新一个条目。在这种情况下,如果我只想更新UserNamePassword-有一个异常抛出,因为Age不能是Null。如何解决这个问题?

InnerException = {"Cannot insert the value NULL into column 'Age', table 'DBFFFF.dbo.Users'; column does not allow nulls. INSERT fails.rnThe statement has been terminated."}

代码
public class User
{
public int Id{ get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Age { get; set; }
}
public class UserEntityConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(c => c.Id);
builder.Property(c => c.UserName)
.IsRequired(true);
builder.Property(c => c.Password )
.IsRequired(true);
builder.Property(c => c.Age )
.IsRequired(true); 
}
}
public async Task<string> UpdateUs(User u)
{
_dbCont.Update(u);
await _dbCont.SaveChangesAsync();
return "ok";
}

你的问题在这里:

public async Task<string> UpdateUs(User u)
{
_dbCont.Update(u);
await _dbCont.SaveChangesAsync();
return "ok";
}

我假设您的UpdateUs呼叫站点看起来像这样:

User u = new User()
{
Id = 123,
UserName = "foobar"
};
await UpdateUs(u);
  • 注意上面的代码没有为AgePassword设置任何值

    • 和你不能存储用户的密码为明文!
  • …但是你的代码调用了DbContext.Update

    • …这基本上告诉EF对象u现在代表了实体的当前状态,Id = 123包括Age = null",这是不是你想要的。
      • 我假设您实际想要的是EF只考虑更新的UserName属性,而忽略尚未设置的其他非关键属性(PasswordAge)。
  • 另外,我得到的感觉,你使用你的实体类作为可变视图模型(例如在ASP。. NET或WPF)。您不应该这样做,因为实体对象表示持久的业务数据状态,它不表示内存中可变的UI状态。

    • 此外,视图模型需要实体类型没有的额外注释和成员。例如,"编辑用户"视图模型需要两个密码字段("New password"one_answers"确认新密码"),这就是为什么视图模型有单独的类,即使它们与实体类具有相同的成员。

无论如何,正确的解决方案(假设您仍然想使用您的class User作为内部DTO),是使用Attach并在您正在更新的属性上设置IsModified

一样:

public async Task< UpdateUserAsync(User u)
{
// Preconditions:
if( u is null ) throw new ArgumentNullException(nameof(u));
if( u.Id == default ) throw new ArgumentException( message: "User's Id is not set.", paramName: nameof(u) );
// 
this.dbContext.Users.Attach( u );
var entry = this.dbContext.Entry( u );
if( u.UserName != null ) entry.Property( x => x.UserName ).IsModified = true;
if( u.Age      != null ) entry.Property( x => x.Age      ).IsModified = true;
this.dbContext.Configuration.ValidateOnSaveEnabled = false; // <-- Only do this if necessary.
Int32 rowCount = await this.dbContext.SaveChangesAsync();
if( rowCount != 1 ) throw new InvalidOperationException( "No rows (or too many rows) were updated." );
}

我想这将是一个有帮助的答案。当您执行update

时,可以忽略特定的字段。
public async Task<string> UpdateUser(User u)
{
_dbCont.Update(u);
_dbCont.Entry(u).Property(x => x.Age).IsModified = false;
await _dbCont.SaveChangesAsync();
return "ok";
}

使用下面的配置,您将使年龄字段不可为空。

builder.Property(c => c.Age ).IsRequired(true); 

删除IsRequired(true);配置如下:

builder.Property(c => c.Age ); 

最新更新