我一直在探索在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查询数据库更新

我知道这是一件微不足道的事情,但我可能错过了一个简单的解决方案。如果没有,方法一将占上风;-)


当前回答

foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

其他回答

foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

已经有一些非常好的答案,但我想发表我的意见。下面是一个将视图对象转换为实体的非常简单的方法。简单的想法是,只有存在于视图模型中的属性才会被写入实体。这类似于@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次点击,一次加载原始实体,一次保存它。

对我来说,这种方法的简单性和低维护需求超过了增加的数据库调用。

我真的很喜欢公认的答案。我相信还有另一种方法来解决这个问题。假设您有一个非常短的属性列表,您不希望在视图中包含这些属性,因此在更新实体时,这些属性将被省略。假设这两个字段是Password和SSN。

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

这个例子允许您在向Users表和View中添加新字段后,基本上不需要考虑业务逻辑。

只是为了增加更多的选择。您还可以从数据库中获取对象,并使用像auto Mapper这样的自动映射工具来更新您想要更改的记录部分。

你正在寻找:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();