我一直在探索在ASP实体框架5中编辑/更新记录的不同方法。NET MVC3环境,但到目前为止,他们没有一个tick所有的盒子我需要。我会解释为什么。
我发现了三种方法,我将在这里介绍它们的优缺点:
方法1 -加载原始记录,更新每个属性
var original = db.Users.Find(updatedUser.UserId);
if (original != null)
{
original.BusinessEntityId = updatedUser.BusinessEntityId;
original.Email = updatedUser.Email;
original.EmployeeId = updatedUser.EmployeeId;
original.Forename = updatedUser.Forename;
original.Surname = updatedUser.Surname;
original.Telephone = updatedUser.Telephone;
original.Title = updatedUser.Title;
original.Fax = updatedUser.Fax;
original.ASPNetUserId = updatedUser.ASPNetUserId;
db.SaveChanges();
}
Pros
可以指定哪些属性更改
视图不需要包含每个属性
Cons
2 x查询数据库加载原始,然后更新它
方法2 -加载原始记录,设置更改值
var original = db.Users.Find(updatedUser.UserId);
if (original != null)
{
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();
}
Pros
只有修改后的属性才会被发送到数据库
Cons
视图需要包含每个属性
2 x查询数据库加载原始,然后更新它
方法3 -附加更新的记录并将状态设置为EntityState。修改
db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();
Pros
1 x查询数据库更新
Cons
不能指定更改哪些属性
视图必须包含所有属性
问题
我的问题是;有没有一种干净利落的方法可以让我实现这些目标?
可以指定哪些属性更改
视图不需要包含每个属性(比如密码!)
1 x查询数据库更新
我知道这是一件微不足道的事情,但我可能错过了一个简单的解决方案。如果没有,方法一将占上风;-)
我已经在我的存储库基类中添加了一个额外的更新方法,它类似于脚手架生成的更新方法。它不是将整个对象设置为“modified”,而是设置一组单独的属性。(T是类的泛型参数。)
public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
Context.Set<T>().Attach(obj);
foreach (var p in propertiesToUpdate)
{
Context.Entry(obj).Property(p).IsModified = true;
}
}
然后调用,例如:
public void UpdatePasswordAndEmail(long userId, string password, string email)
{
var user = new User {UserId = userId, Password = password, Email = email};
Update(user, u => u.Password, u => u.Email);
Save();
}
我喜欢去数据库一趟。不过,为了避免重复属性集,最好在视图模型中这样做。我还没有这样做,因为我不知道如何避免将视图模型验证器上的验证消息带入域项目。
我已经在我的存储库基类中添加了一个额外的更新方法,它类似于脚手架生成的更新方法。它不是将整个对象设置为“modified”,而是设置一组单独的属性。(T是类的泛型参数。)
public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
Context.Set<T>().Attach(obj);
foreach (var p in propertiesToUpdate)
{
Context.Entry(obj).Property(p).IsModified = true;
}
}
然后调用,例如:
public void UpdatePasswordAndEmail(long userId, string password, string email)
{
var user = new User {UserId = userId, Password = password, Email = email};
Update(user, u => u.Password, u => u.Email);
Save();
}
我喜欢去数据库一趟。不过,为了避免重复属性集,最好在视图模型中这样做。我还没有这样做,因为我不知道如何避免将视图模型验证器上的验证消息带入域项目。
已经有一些非常好的答案,但我想发表我的意见。下面是一个将视图对象转换为实体的非常简单的方法。简单的想法是,只有存在于视图模型中的属性才会被写入实体。这类似于@Anik Islam Abhi的回答,但具有零传播。
public static T MapVMUpdate<T>(object updatedVM, T original)
{
PropertyInfo[] originalProps = original.GetType().GetProperties();
PropertyInfo[] vmProps = updatedVM.GetType().GetProperties();
foreach (PropertyInfo prop in vmProps)
{
PropertyInfo projectProp = originalProps.FirstOrDefault(x => x.Name == prop.Name);
if (projectProp != null)
{
projectProp.SetValue(original, prop.GetValue(updatedVM));
}
}
return original;
}
Pros
视图不需要拥有实体的所有属性。
当您向视图添加删除属性时,您不必更新代码。
完全通用的
Cons
对数据库进行2次点击,一次加载原始实体,一次保存它。
对我来说,这种方法的简单性和低维护需求超过了增加的数据库调用。