2016-11-18 65 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!這將幫助我! –