【发布时间】:2016-02-17 14:09:44
【问题描述】:
当我想保存从表单发回的对象,但从生成的 SQL 语句中排除特定字段时,会出现问题。在这种情况下,我不想在用户编辑表单中包含密码字段。
一个编辑 HttpPost 控制器方法包含以下内容:
db.Users.Attach(user);
db.Entry(user).State = EntityState.Modified;
db.Entry(user).Property(x => x.Password).IsModified = false;
db.SaveChanges();
我假设 .IsModified 语句意味着生成的 SQL 将包含一个没有密码字段的 UPDATE 语句,因此不会用数据库中的 null 覆盖现有的密码值。
但是,情况并非如此,EF 的工作方式似乎略有不同。我的用户类及其关联的元数据类没有指定密码字段是必需的,但在执行时,调用 SaveChanges 时会抛出“需要密码字段”DbEntityValidationException。
一种解决方案是将密码字段及其值作为隐藏的表单字段包含在内,这在大多数情况下就足够了,但在这种情况下并不是一个好主意,因为密码、散列或其他方式是相当敏感的数据。
经过进一步检查,在我们使用数据库优先方法的这种情况下,.edmx 文件的密码字段似乎包含一个“非空”指令。当 EF 来执行实际保存时,会对其进行检查并引发异常。
在我看来,这并不完全直观,但一旦知道它就可以解决。
我的解决方案是为排除字段提供一个值并保留 .IsModified 语句。这意味着 DbEntityValidationException 不会被抛出,因为 EF 看到包含值的 Password 字段(如 .edmx 文件中所述)但由于 IsModified 为 false 而实际上并未写入数据库。例如
user.Password = "not required";
db.Users.Attach(user);
db.Entry(user).State = EntityState.Modified;
db.Entry(user).Property(x => x.Password).IsModified = false;
db.SaveChanges();
是否有更好的解决方案,因为使用上面的虚拟值似乎有点 hack?
【问题讨论】:
-
您是否考虑过使用 ViewModel 并减少您移动的不需要的数据量?
-
我们通常使用 viewmodel 方法,但在这种情况下,我们决定将我们的 db 模型暴露给表示层,以便我们可以充分使用 vs2015 中的脚手架/模板功能,同时首先使用 db方法。这样做的好处是删除了所有视图模型和映射相关代码(自动映射器等),这在简化我们的代码方面非常有用。过去,我们在将业务逻辑放置在视图模型映射中时遇到过麻烦。权衡是我们必须严格控制数据库更改/重新脚手架,因为我们意识到要引入紧密耦合。
标签: c# sql-server asp.net-mvc entity-framework entity-framework-6