我接受来自用户的3个字段。所有3个字段都必须输入。查看下面的实体配置—EntityConfiguration
中的所有3个字段都被标记为Required
。
当我将新记录保存到数据库时,这可以完美地工作。但是,现在我需要更新一个条目。在这种情况下,如果我只想更新UserName
和Password
-有一个异常抛出,因为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);
注意上面的代码没有为
Age
和Password
设置任何值- 和你不能存储用户的密码为明文!
…但是你的代码调用了
DbContext.Update
…- …这基本上告诉EF对象
u
现在代表了实体的当前状态,Id = 123
包括Age = null
",这是不是你想要的。- 我假设您实际想要的是EF只考虑更新的
UserName
属性,而忽略尚未设置的其他非关键属性(Password
和Age
)。
- 我假设您实际想要的是EF只考虑更新的
- …这基本上告诉EF对象
另外,我得到的感觉,你使用你的实体类作为可变视图模型(例如在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 );