简体   繁体   中英

Unable to determine the principal end of the etaxiDataModel relationship. Multiple added entities may have the same primary key

SettlementShift的映射定义 I have been struggling with this problem for some time now and am not able to resolve this. Have read multiple posts and tried several different solutions but nothing has worked. Now I feel like I have come to a stop and really need help with this.

I am using EF 5+ with an DB first and edmx file. I have 3 different tables in my DB: 1. Settlement 2. Cost 3. Shift

Settlement has a collection of both Cost and Shift (with a link table) connected by Association in my edmx file.

在我的数据库中包含链接表的结算表 I need to insert a new Settlement in my db with a reference to an already existing Cost and Shift collections. Shifts and Costs included in my Settlement entity I am trying to insert contains all there related data and none of those are modified in any way (same as I retrieved from db). Here in my method of inserting the entity into my db.

public bool CreateSettlement(Settlement settlement)
    {
        bool _success;

        var _context = new EtaxiEnteties();// ObjectFactory.Get<IETaxiEntitiesContext>();

            try
            {
                var _newSettlement = new Settlement
                                         {
                                             CreateDate = settlement.CreateDate,
                                             Driver = settlement.Driver,
                                             DriverID = settlement.DriverID,
                                             Car = settlement.Car,
                                             CarID = settlement.CarID,
                                             DocPath = settlement.DocPath
                                         };
                foreach (var _shift in settlement.Shifts)
                {
                    //var _sh = _context.Shifts.Find(_shift.ShiftID);
                    //_context.Entry(_sh).CurrentValues.SetValues(_shift);
                    _newSettlement.Shifts.Add(_shift);
                }

                foreach (var _cost in settlement.Costs)
                {
                    ////var _sh = _context.Costs.Find(_cost.CostID);
                    ////_context.Entry(_sh).CurrentValues.SetValues(_cost);
                    _newSettlement.Costs.Add(_cost);
                }
                _context.Settlements.Add(_newSettlement);

                _success = _context.SaveChanges() > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        return _success;
    }

Any help on the issue would be MUCH appreciated.

Here is how I am adding the Cost and Shift to my collection:

I create a Settlement in page:

_settlement = new Settlement
                            {
                                CreateDate = DateTime.Now,
                                Driver = _driver,
                                DriverID = _driver.DriverID,
                                Car = _car,
                                CarID = _car.CarID,
                                DocPath = _path
                            };

then when I create a pdf file with selected rows from 2 separated grid views:

   foreach (GridDataItem _selectedRow in gwShifts.MasterTableView.Items)
            {
                if (_selectedRow.Selected)
                {
                    var _shift =
                        _diaryRepository.GetShiftByID((int) _selectedRow.GetDataKeyValue("ShiftID")).FirstOrDefault();

                    if (_shift != null)
                    {
                        _settlement.Shifts.Add(_shift);
                        _settlementData.Shifts.Add(_shift);
                        _settlementData.SplitPercentace = GetTemplateValue(_selectedRow, "lblSplit");
                        _settlementData.SettlementAmount = GetTemplateValue(_selectedRow, "lblSettlementAmount");

                        if (_settlementData.Shifts != null)
                        {
                            _tableShifts.AddCell(
                                new PdfPCell(
                                    new Phrase(
                                        _settlementData.Shifts.FirstOrDefault().ShiftDate.ToShortDateString(),
                                        _bodyFont)) {Border = 0});
                            _tableShifts.AddCell(
                                new PdfPCell(
                                    new Phrase(
                                        string.Format("{0:c}", _settlementData.Shifts.FirstOrDefault().GrossAmount),
                                        _bodyFont)) {Border = 0});
                            _tableShifts.AddCell(
                                new PdfPCell(
                                    new Phrase(
                                        string.Format("{0:c}", _settlementData.Shifts.FirstOrDefault().MoneyAmount),
                                        _bodyFont)) {Border = 0});
                            _tableShifts.AddCell(new PdfPCell(new Phrase(_settlementData.SplitPercentace, _bodyFont))
                                                     {Border = 0});
                            _tableShifts.AddCell(
                                new PdfPCell(new Phrase(_settlementData.SettlementAmount, _boldTableFont))
                                    {Border = 0});

                            _totalAmount.AddRange(new[]
                                                      {
                                                          Convert.ToInt32(
                                                              _settlementData.SettlementAmount.Replace(".", "").
                                                                  Replace(",", "").Replace("kr", ""))
                                                      });
                            _settlementData.Shifts.Remove(_shift);
                        }
                    }
                }
            }

            var _summaryCell =
                new PdfPCell(new Phrase("Upphæð: " + string.Format("{0:c}", _totalAmount.Sum()), _boldTableFont))
                    {
                        Border = 0,
                        Colspan = 5,
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Padding = 5,
                        BorderWidthTop = 1
                    };
            _tableShifts.AddCell(_summaryCell);

            if (_totalAmount.Count != 0)
                _totalAmount.Clear();
        }

there you see how I add the Shift to this Settlement entity:

     var _shift =
                        _diaryRepository.GetShiftByID((int) _selectedRow.GetDataKeyValue("ShiftID")).FirstOrDefault();

                    if (_shift != null)
                    {
                        _settlement.Shifts.Add(_shift);

then I send this to the reporistory (see method above)

        if(_driverRepository.CreateSettlement(_settlement))
            {
                SetMessage("Uppgjör hefur verið skapað og sent bílstjóra ef e-póstur er skráður á viðkomandi bílstjóra.", "Uppgjör skapað");
                pnlSettlement.Visible = false;
                pnlDocCreation.Visible = false;
                pnlResult.Visible = false;   
            }

I also tried to simply add param settlement directly to the context but got similar error.

I think this has to do with how you're populating the Shifts and Costs collection. You're trying to add already created records (ie they already have their primary key values set) to be saved with the new Settlement entity, but I believe that Entity Framework isn't trying to create new ones that are linked to your new Settlement entity but rather save them to the table as is. In such a case you would indeed have a situation where multiple entities have the same primary key.

I would try the following (I'll show you using the Shifts loop only, but you should be able to apply it to the Costs loop as well):

foreach (var _shift in settlement.Shifts)
{
  var newShift = new Shift { /*Copy all of the values from _shift here*/ };
  _newSettlement.Shifts.Add(_shift);
  context.Shifts.Add(newShift);
}

If that doesn't work I would suggest debugging Costs and Shifts to make sure that you don't have any duplicates in those collections.

If you don't want new Shifts & Costs then I can only assume you need to repoint the existing ones to the new Settlement

foreach (var shift in settlement.Shifts)
{  
    //either
    shift.Settlement = newSettlement;
    //or
    shift.SettlementId = newSettlement.SettlementId;
    //depending on your object model
}

I've just realised that I have misunderstood the question. There are 2 additional tables not shown in the diagram (Costs & Shifts). The problem is trying to create SettlementCost and SettlementShift entities that connect Settlement to Costs\\Shifts .

OK, came up with a "ugly" solution on this..but it is resolved. Changed the Model to be one(Settlement) -> many(Shift or Cost) relationship.

I create a new Settlement and save this one to the DB. Retrieve each Shift and Cost from the DB update SettlementID on each and save these to the DB.

 try
        {
            var _newSettlement = new Settlement
                                        {
                                            CreateDate = settlement.CreateDate,
                                            DriverID = settlement.DriverID,
                                            CarID = settlement.CarID,
                                            DocPath = settlement.DocPath
                                        };
            Add(_newSettlement);
            _success = SaveWithSuccess() > 0;

            var _settlement = GetAll().FirstOrDefault(x => x.SettlementID == _newSettlement.SettlementID);

            if (_success)
            {
                foreach (var _shift in settlement.Shifts)
                {
                    var _sh = _diaryRepository.GetShiftByID(_shift.ShiftID).FirstOrDefault();
                    _sh.SettlementID = _settlement.SettlementID;
                    _diaryRepository.UpdateShift(_sh);
                }

                foreach (var _cost in settlement.Costs)
                {
                    var _ch = _costRepository.GetCostByID(_cost.CostID);
                    _ch.SettlementID = _settlement.SettlementID;
                    _costRepository.UpdateCost(_ch);

                }
            }
        }

not a pretty one, but it resolves the problem. I am not concerned about the DB request load..it will not be that high in this case.

I would think there is a nicer solution to this but I was not able to find it at this time.

Thanks for all your efforts to help :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM