2016-11-18 69 views
0

我试图做一个主从Web窗体与实体框架的工作,并在同一页面上进行插入和更新。我是EF新手,所以我必须在这里犯很多错误。你能帮我指点一下在EF上执行插入/更新的最佳实践吗?我在这里做错了什么?如何插入实体框架/更新主细?

在这段代码中,“新”的模式运作良好,但在“编辑”模式得到这个错误:“一个实体对象不能被IEntityChangeTracker的多个实例引用”。

OrdersEntities ordersEntities = new OrdersEntities(); 

    private Order myOrder 
    { 
     get { return (Order)Session["myOrder"]; } 
     set { Session["myOrder"] = value; } 
    } 

    public DataTable dtOrderDetails 
    { 
     get { return (DataTable)ViewState["dtOrderDetails"]; } 
     set { ViewState["dtOrderDetails"] = value; } 
    } 

    private string Mode 
    { 
     get { return (string)ViewState["mode"]; } 
     set { ViewState["_modo"] = value; } 
    } 

    private void btnSaveOrder_Click(object sender, EventArgs e) 
    { 
     if (dtOrderDetails.Rows.Count > 0) 
     { 
      using (ordersEntities) 
      { 
       using (var contextTransaction = ordersEntities.Database.BeginTransaction()) 
       { 
        try 
        { 
         if (Mode == "New") 
         { 
          Order newOrder = new Order(); 
          OrderDetails newOrderDetails; 

          int maxOrderNumber = ordersEntities.Order.Select(o => o.OrderNumber).DefaultIfEmpty(0).Max(); 
          maxOrderNumber++; 

          newOrder.OrderNumber = maxOrderNumber; 
          newOrder.Date = DateTime.ParseExact(txtOrderDate.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture); 
          newOrder.CustomerID = Convert.ToInt32(ddlCustomer.SelectedValue); 
          newOrder.Status = 1; 

          ordersEntities.Orders.Add(newOrder); 

          foreach (DataRow dt in dtOrderDetails.Rows) 
          { 
           newOrderDetails = new OrderDetails(); 
           newOrderDetails.OrderNumer = maxOrderNumber; 
           newOrderDetails.ProductId = Convert.ToInt32(dt["ProductId"]); 
           newOrderDetails.Quantity = Convert.ToInt32(dt["Quantity"]); 

           ordersEntities.OrderDetails.Add(newOrderDetails); 
          } 

          ordersEntities.SaveChanges(); 
          contextTransaction.Commit(); 

          myOrder = newOrder; 
         } 

         if (Mode == "Edit") 
         { 
          Order editedOrder = myOrder; 
          OrderDetails editedOrderDetails; 

          editedOrder.Date = DateTime.ParseExact(txtOrderDate.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture); 
          editedOrder.CustomerID = Convert.ToInt32(ddlCustomer.SelectedValue); 

          ordersEntities.Order.Attach(editedOrder); 
          ordersEntities.Entry(editedOrder).State = System.Data.Entity.EntityState.Modified; 

          editedOrder.OrderDetails.Clear(); 

          foreach (DataRow dt in dtOrderDetails.Rows) 
          { 
           editedOrderDetails = new OrderDetails(); 
           editedOrderDetails.OrderNumer = editedOrder.OrderNumber; 
           editedOrderDetails.ProductId = Convert.ToInt32(dt["ProductId"]); 
           editedOrderDetails.Quantity = Convert.ToInt32(dt["Quantity"]); 

           ordersEntities.OrderDetails.Add(editedOrderDetails); 
          } 

          ordersEntities.SaveChanges(); 
          contextTransaction.Commit(); 
         } 
        } 
        catch (Exception ex) 
        { 
         contextTransaction.Rollback(); 
        } 
       } 
      } 
     } 
    } 
+0

哇,这太可怕了。 –

+0

我知道,有什么帮助吗? –

+0

我会在几分钟/小时内回复您。 –

回答

1

下面是你应该如何处理它。

这将是最好的,如果你抽象的DbContext了,这个简单的接口:

public interface IDataRepository : IDisposable 
{ 
    IDbSet<Order> Orders { get; set; } 

    void Save(); 
} 

当然,你的IDataRepository实现是基于的EntityFramework。请注意,您需要有一个dataRepositoryConnection连接字符串中你的web.config文件:

public class EfDataRepository : DbContext, IDataRepository 
{ 
    public EfDataRepository() : base("dataRepositoryConnection") 
    { 
    } 

    public IDbSet<Order> Orders { get; set; } 

    public void Save() 
    { 
     this.SaveChanges(); 
    } 
} 

以我的经验,你还需要一个“工厂”,它给你的数据存储库的新实例。这允许您成为实例的“所有者”,并且可以安全地处置它。请注意,与DataContext的交互应该是最小的 - 你做你的工作团结并摆脱它。不要重复使用!您将在下面看到它。

public class DataRepositoryFactory<T> where T : IDataRepository 
{ 
    private Type dataRepositoryImplementationType; 

    public DataRepositoryFactory(T dataRepositoryImplementation) 
    { 
     if (dataRepositoryImplementation == null) 
     { 
      throw new ArgumentException("dataRepositoryImplementation"); 
     } 

     this.dataRepositoryImplementationType = dataRepositoryImplementation.GetType(); 
    } 

    public T Create() 
    { 
     return (T)Activator.CreateInstance(this.dataRepositoryImplementationType); 
    } 
} 

在你的控制器(如果它是MVC应用程序),或页面后端(形式),这将是最好的,如果你使用微软统一获得的DataRepositoryFactory一个实例。目前,手动施工也足够了。

IDataRepository dataRepository = new EfDataRepository(); 
var dataRepositoryFactory = new DataRepositoryFactory<IDataRepository>(dataRepository); 

此外,你不需要所有这些交易/提交你放的东西。它应该对你是透明的。 EF隐式支持它,你不必明确表示它。

// See, now you are the 'owner' of the dataRepository 
using (var dataRepository = this.dataRepositoryFactory.Create()) 
{ 
    if (Mode == "New") 
    { 
     Order newOrder = new Order(); 

     // This doesn't make sense. Either generate a random order number (e.g. a Guid), or just use the Order.Id as an order number, although I don't recommend it. 
     int maxOrderNumber = dataRepository.Orders.Select(o => o.OrderNumber).DefaultIfEmpty(0).Max(); 
     maxOrderNumber++; 

     newOrder.OrderNumber = maxOrderNumber; 
     newOrder.Date = DateTime.ParseExact(txtOrderDate.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture); 
     newOrder.CustomerID = Convert.ToInt32(ddlCustomer.SelectedValue); 
     newOrder.Status = 1; 

     dataRepository.Orders.Add(newOrder); 

     foreach (DataRow dt in dtOrderDetails.Rows) 
     { 
      OrderDetails newOrderDetails = new OrderDetails(); 
      newOrderDetails.OrderNumer = maxOrderNumber; 
      newOrderDetails.ProductId = Convert.ToInt32(dt["ProductId"]); 
      newOrderDetails.Quantity = Convert.ToInt32(dt["Quantity"]); 

      newOrder.OrderDetails.Add(newOrderDetails); 
     } 

     myOrder = newOrder; 
    } 

    if (Mode == "Edit") 
    { 
     Order editedOrder = dataRepository.Orders.FirstOrDefault(o => o.Id == myOrder.Id); 

     editedOrder.Date = DateTime.ParseExact(txtOrderDate.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture); 
     editedOrder.CustomerID = Convert.ToInt32(ddlCustomer.SelectedValue); 
     editedOrder.OrderDetails.Clear(); 

     foreach (DataRow dt in dtOrderDetails.Rows) 
     { 
      OrderDetails editedOrderDetails = new OrderDetails(); 
      editedOrderDetails.OrderNumer = editedOrder.OrderNumber; 
      editedOrderDetails.ProductId = Convert.ToInt32(dt["ProductId"]); 
      editedOrderDetails.Quantity = Convert.ToInt32(dt["Quantity"]); 

      editedOrder.OrderDetails.Add(editedOrderDetails); 
     } 
    } 

    dataRepository.Save(); 
} 

而且,我敢肯定你已经安装OrderOrderDetails类之间的关系不正确,在你的EF代码优先方法。

这是错误的:

OrderDetails newOrderDetails = new OrderDetails(); 
newOrderDetails.OrderNumer = maxOrderNumber; 

如果您张贴在这里,我可以修复它们。

+0

非常感谢Hristo!这将帮助我! –