ASP.NET MVC实体框架 - 实体更新 - 使用空值覆盖数据库值

时间:2013-01-12 18:40:34

标签: asp.net asp.net-mvc entity-framework

我目前正在寻找一种设计模式,或者更确切地说是为Repository<Entity>.Update()应用程序实现ASP.NET MVC 4方法的最佳实践,该方法使用Entity Framework 5和Code First方法。

问题: 我遇到的问题是,当从数据库查询实体并在视图上显示时,它可能没有填充所有属性。因此,在调用repository.Update(entity)方法时,传递给Update()方法的实体可能具有具有空值的未绑定属性。但是,它们可能在数据库中有一些值。以下代码中的示例Customer.Misc

所以问题来了。根据这种方法,在第一次Update()方法调用之后,所有未绑定在视图上的属性都将在数据库中设置为Null。

class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Misc { get; set; }
}

[HttpGet]
public ActionResult Update(int id)
{
    Repository<Customer> repo = new Repository<Customer>();
    return View(repo.GetById(id)); // View only binds Customer.Name
}

[HttpPost]
public ActionResult Update(Customer customer)
{
    Repository<Customer> repo = new Repository<Customer>();
    repo.Update(customer); // Customer.Misc is null
    ...
}

public void Update(TEntity entity)
{
    var entry = DbContext.Entry<TEntity>(entity);
    if (entry.State == EntityState.Detached)
    {
        ObjectContext.ApplyCurrentValues(EntitySetName, entity);
    }
    DbContext.SaveChanges();
}

我能想到的解决方案:

  • 在视图上绑定所有实体属性:

    • 我认为这是不可行的,同时它可能导致性能问题,因为所有属性都会被填充。
  • 实现自定义方法以复制属性值,以避免复制空值。

    • EntityHelper.CopyNotNullValues(source, target)并忽略源实体中的空值。如果我们这样做,我们可能无法在需要时将任何值设置为null。
  • 使用域模型实现视图模型并来回转换数据。

    • 到目前为止,这是我能想到的最佳方法。绑定到视图模型的所有属性将始终填充,在更新POST上,将所有视图模型值复制到域模型。

非常感谢您对此的看法。

1 个答案:

答案 0 :(得分:0)

在Entity Framework中,使用ChangeObjectState或ApplyCurrentValues将导致数据丢失。在这种情况下解决此问题的唯一方法是附加输入实体并标记要更新的属性。见下面的例子:

    public void Update(TEntity entity, string[] updatedProperties)
    {
        DbContext.Entities.Attach(entity);
        var entry = DbContext.Entry<TEntity>(entity);
        for (int i = 0; i < updatedProperties.Length; i++)
        {
            entry.SetModifiedProperty(updatedProperties[i]);
        }
        DbContext.SaveChanges();
    }

    [HttpPost]
    public ActionResult Update(Customer customer)
    {
        Repository<Customer> repo = new Repository<Customer>();
        repo.Update(customer, new string[]{ "Name" }); // Only update name
        ...
    }

这是我能想到的最佳解决方案。你想拥有最少的代码和良好的性能。这很难找到一份简单而有报酬的工作。