1

So the problem I'm having is the following. When going into this if statement, then I want to delete all the entries with ClearDbInstallForGroupAndHeader() from table InstallationBOM. Then I want to add all the entries within NewInstallationBoms into my InstallationBOM table and while doing this calculating total cost, but when I want to add it with this line db.InstallationBOMs.Add(newInstallationBom);, I get the following error:
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

 if (InstallationSelected)
 {
      bool newEntry = true;
      if (SelectedQuoteDetails != null)
      {
          QuoteDetail theQuoteDetail = SelectedQuoteDetails.FirstOrDefault(X => X.GroupNr == groupID && X.LineType == "I");
          if (theQuoteDetail != null)
          {
               this.ClearDbInstallForGroupAndHeader();
               int position = SelectedQuoteDetails.IndexOf(theQuoteDetail);
               newEntry = false;
               theQuoteDetail.Quantity = InstallQty;
               theQuoteDetail.UnitCost = InstallCost;
               theQuoteDetail.UnitPrice = InstallPrice;
               SelectedQuoteDetails[position] = theQuoteDetail;

               db.QuoteDetails.Attach(theQuoteDetail);
               db.Entry(theQuoteDetail).State = EntityState.Modified;
               db.SaveChanges();

              decimal totalInstallationCost = 0;
              totalInstallationCost = AddInstallToDbCalcTotalCost(theQuoteDetail.Line.Value, groupID);

              newLines.UnitCost = totalInstallationCost;
              newLines.UnitPrice = newLines.UnitCost * (1 + (Settings.MarginPercentage / 100));

              InstallCost = newLines.UnitCost ?? 0;
              InstallPrice = newLines.UnitPrice ?? 0;                                        

              RaisePropertyChanged(() => SelectedQuoteDetails);

          }
      }
  }

  public void ClearDbInstallForGroupAndHeader()
    {
        try
        {
            using (QuoteConfiguratorEntities db = Utilities.GetContext())
            {
                List<InstallationBOM> dbList = db.InstallationBOMs.Where(x => x.QuoteHeaderId == this.SelectedQuoteHeader.ID && x.GroupNr == this.SelectedGroup.ID)
                                                        .ToList();
                foreach (InstallationBOM existingInstallationBom in dbList)
                {
                    db.InstallationBOMs.Remove(existingInstallationBom);
                }
                db.SaveChanges();
            }

        }
        catch (Exception ex)
        {
            this.Message = ex.Message + "\n\n" + ex.StackTrace;
            this.ShowErrorMessage();
        }
    }

    public decimal AddInstallToDbCalcTotalCost(decimal pLine, long pGroupNr)
    {
        decimal totalInstallationCost = 0;
        try
        {
            using (QuoteConfiguratorEntities db = Utilities.GetContext())
            {
                foreach (InstallationBOM newInstallationBom in this.NewInstallationBoms)
                {
                    newInstallationBom.QuoteHeaderId = this.SelectedQuoteHeader.ID;
                    newInstallationBom.GroupNr = pGroupNr;
                    newInstallationBom.LineNumber = pLine;
                    totalInstallationCost += (newInstallationBom.Quantity.Value *
                                              newInstallationBom.Cost.Value);
                    db.InstallationBOMs.Add(newInstallationBom);                       
                    db.SaveChanges();   
                }
            }
        }
        catch (Exception ex)
        {
            this.Message = ex.Message + "\n\n" + ex.StackTrace;
            this.ShowErrorMessage();
        }
        return totalInstallationCost;
    }

public void OpenInstallationOptionsWindow(bool AsThread = false)
    {
        try
        {
            if (AsThread)
            {
                this.Busy = true;
                this._Thread = new Thread(() => QuoteConfiguratorViewModel.OpenInstallationOptionsWindow(this));
                this._Thread.IsBackground = true;
                this._Thread.Start();
            }
            else
            {
                using (QuoteConfiguratorEntities db = Utilities.GetContext())
                {
                    ObservableCollection<InstallationBOM> installBomListGroup = new ObservableCollection<InstallationBOM>(db.InstallationBOMs.Where(x => x.QuoteHeaderId == this.SelectedQuoteHeader.ID
                        && x.GroupNr == this.SelectedGroup.ID).ToList());
                    if (installBomListGroup != null)
                    {
                        if (!installBomListGroup.Any())
                        {
                            ClearInstallationBomEntry();
                            NewInstallationBoms = new ObservableCollection<InstallationBOM>();
                        }
                        else if (installBomListGroup.Any())
                        {
                            NewInstallationBoms = installBomListGroup;
                        }
                    }                        

                    Messenger.Default.Send<OpenInstallationWindow>(new OpenInstallationWindow());

                }

            }
        }
        catch (Exception ex)
        {
            this.Message = Utilities.GetError(ex);
        }
    }
Ruaan Volschenk
  • 717
  • 2
  • 11
  • 23

1 Answers1

3

The problem is NewInstallationBoms are attached in a context. But you try to add them in another context in AddInstallToDbCalcTotalCost.

Solution 1: You should use same context. Detailed answer

Solution 2: You should first detach them in first context and attach them in second context. Detailed answer.

Solution 3 (Credits to grek40): If you use AsNoTracking() in first context. It will not be tracked/cached. Therefore you can safely use it in second context.

In your stiuation it's better to follow solution 1. If you use dependency injection container, you can make your dbcontext as per request. Other than this,you can manage lifetime of dbcontext on upper level or you can make your class disposable and manage db context in your class.

Community
  • 1
  • 1
Erkan Demirel
  • 4,302
  • 1
  • 25
  • 43