使用MVC4和EF5进行更改的最佳实践

时间:2013-03-02 08:52:33

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

我有一个CustomerOrder视图,我想更改现有的CustomerOrder。

我有一个非常简化的viewmodel看起来像这样:

        public class CustomerOrderViewModel
    {
        public int ID { get; set; }
        public Customer Customer { get; set; }
        public DateTime Date { get; set; }
        public IEnumerable<OrderRow> OrderRows { get; set; } 

    }

    public class OrderRow
    {
        public int id { get; set; }
        public int price { get; set; }
    }

    public class Customer
    {
        public string Name { get; set; }    
    }

我还有一个包含映射表/字段的数据库。

在我的GET操作方法中,我在Automapper的帮助下加载订单,如下所示:

  var customerOrder =  using (var ctx = new My_Entities()) {
                return ctx.CustomerOrders.
                    Include("Orderrows").
                    Include("Customer").
                    Single(o => o.CustomerOrderID == id); 
            }
  var model= AutoMapper.Mapper.DynamicMap<DataAccessLayer.CustomerOrder, CustomerOrderViewModel>(customerOrder);

在视图中我使用Knockout绑定到那里的viewmodel,用户可以在其中更新CustomerOrder。这包括编辑客户信息和添加新的订单等。

然后在帖子中将ViewModel映射回ObjectContext CustomerOrder:

var customerOrderToBeSaved =
            AutoMapper.Mapper.DynamicMap<CustomerOrderViewModel, CustomerOrder>(
                customerOrderViewModel);
        try
        {
            using (var ctx = new MyEntities())
            {

                ctx.CustomerOrders.Attach(customerOrderToBeSaved);
                ctx.CustomerOrders.ApplyCurrentValues(customerOrderToBeSaved);
                ...
                ctx.SaveChanges();

            }
        }

我收到错误消息: ObjectStateManager中已存在具有相同键的对象。 ObjectStateManager无法使用相同的键跟踪多个对象。

好的,我能理解。但是我应该怎么做呢?我可以获取现有对象并将更改应用于该对象,因为这确实是我想要的。我试图查找旧的并分离它,但我还没有把它弄糟。也许我是以一种完全错误的方式做到这一点。请指教。

2 个答案:

答案 0 :(得分:3)

您不应附加customerOrderToBeSaved,请参阅MSDN有关ApplyCurrentValues的论据。

  

分离的对象,它具有要应用于原始对象的属性更新。

因此,您必须将实体从数据库加载到上下文中,然后使用具有新值的分离对象加载ApplyCurrentValues

答案 1 :(得分:1)

没有从数据库加载行来更新它。

您可以这样做:

var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);
ctx.Entry( entity ).State = EntityState.Modified;
ctx.SaveChanges();

这将告诉EF发出一个UPDATE SQL语句,该语句会覆盖记录中所有列。

您可以选择要更新的列:

var entity = ctx.CustomerOrders.Attach(customerOrderToBeSaved);

var entry = ctx.Entry( entity );
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
entry.Property( o => o.<ColumnPropertyToUpdate> ).IsModified = true;
...

ctx.SaveChanges();

如果您这样做,EF将仅包含您在UPDATE语句中标记为已修改的列。