EF 6:当我将元素标记为已删除时,集合长度会减少

时间:2014-02-12 13:57:41

标签: c# wpf entity-framework

我正在尝试熟悉EF 6(代码优先),WPF和C#。我使用了两个与一对多关系相关的实体 «模拟»是父母 «echeance»是孩子

public partial class simulation : INotifyPropertyChanged
{

        public long SimulationId { get; set; }

       ...
       ...
       ...

        public virtual ICollection<Echeance> echeancier { get; set; }
        public List<Echeance> echeancierCopy { get; set; }
        ...
        ...
    ...
}


public partial class Echeance : INotifyPropertyChanged
{
    public long EcheanceId { get; set; }
    public long SimulationId { get; set; }
    public virtual simulation simulation { get; set; }
    ...
    ...
    ...
}

实际上,当我想要修改«模拟»时,首先我从数据库中读取它,然后将«echeancier»集合克隆到«echeanceCopy»列表并将数据绑定«echeanceCopy»发送到WPF数据网格,这样我就可以交互式地进行更改在datagrid单元格中。当我想保存模拟时: 有两种情况:

1)新的模拟:我将«echeanceCopy»转移到«echeancier»集合和i saveit。它工作正常。

2)旧模拟:我将«echeanceCopy»转移到«echeancier»集合并保存它。 如果«echeanceCopy»的长度小于«echeancier»那么我必须标记为«echeancier»中存在的已删除元素,而不是«echeanceCopy»。问题是,当我这样做时,«echeancier»集合的长度自动减少(我一步一步地使用调试器),我不明白为什么?。

这里是集合和列表之间转移的代码

private void TransfertToOriginal(simulation item)
    {
        item.echeancierCopy.OrderBy(e => e.EchNumber);
        item.echeancier.OrderBy(e => e.EchNumber);

        int copylen     = item.echeancierCopy.Count();  
        int origlen     = item.echeancier.Count();                  
        try
       {
             if (copylen > origlen)
                for (int ii = 0; ii <= copylen - 1; ii++)
                    {
                       if (ii < origlen) //Copy and mark as Modified
                        EcheanceCopy(item, ii);
                        else //Add the new echeance and mark it as added
                    if (ii >= origlen)
                          {
                            item.echeancier.Add(item.echeancierCopy[ii]);
           base.GetCurrentUoW().RegisterNew<Echeance>(item.echeancier.ElementAt(ii));
                       }
                else
                {
                    if (copylen < origlen)
                    {
                        for (int ii = 0; ii < origlen; ii++)
                        {
                            if (ii < copylen)
                            {
                                EcheanceCopy(item, ii);
                            }
                            else //the echeance is deleted then mark it as deleted 
                            {
    //the following line will cause length of "echeancier" collection to decrease  
   //automatically each time in loop and fire an exception when ii become > length of 
   //"echeancier" ... exception says : index out of limit


      base.GetCurrentUoW().RegisterDeleted<Echeance>(item.echeancier.ElementAt(ii));
                        }
                    }
                  }
             }
           catch (Exception ex)
              {
                _logger.LogException(ex);
                throw ex;
              }

    }



  //Method for copy echeanceCopy-> echeancier
  private void EcheanceCopy(simulation item, int index)
    {
        item.echeancier.ElementAt(index).DateEcheance =    item.echeancierCopy[index].DateEcheance;
        item.echeancier.ElementAt(index).MontantPrincipal = item.echeancierCopy[index].MontantPrincipal;
        item.echeancier.ElementAt(index).MontantInteret = item.echeancierCopy[index].MontantInteret;
        item.echeancier.ElementAt(index).MontantTTC = item.echeancierCopy[index].MontantTTC;
        item.echeancier.ElementAt(index).MontantHT = item.echeancierCopy[index].MontantHT;
        item.echeancier.ElementAt(index).MontantTVA = item.echeancierCopy[index].MontantTVA;
        base.GetCurrentUoW().RegisterChanged<Echeance>(item.echeancier.ElementAt(index));
    }

对不起,我忘记了工作单位的代码

  //Mark entity as deleted
    public void RegisterDeleted<T>(T item) where T : class
    {
        base.Entry<T>(item).State = EntityState.Deleted;

    }


//Mark entity as Modified
public void RegisterChanged<T>(T item) where T : class
    {

        base.Entry<T>(item).State = EntityState.Modified;

    }


//Mark entity as Added
  public void RegisterNew<T>(T item) where T : class
    {
                base.Entry<T>(item).State = EntityState.Added;

    }

这里是保存在数据库中的代码

public override void Modify(simulation item)
    {


        //If we are in Edit mode
         try
         {
             if (item.SimulationId != 0)
             {
                 //Detach the working collection from dbcontext
                 DetachEcheancier(item.echeancierCopy.ToList());

                 //Transfert the working collection to original collection 
                 TransfertToOriginal(item);
             }

             else  //New Simulation
             {
                 //Copy all working collection elements to original collection
                 item.echeancier = new List<Echeance>(item.echeancierCopy);
                 //Mark all elements of original collection as added
                 SetEcheancierAsAdded(item);
             }

             base.Modify(item); //Then save (call SaveChanges() from uow
         }
         catch (Exception ex)
         {
             _logger.LogException(ex);
             throw ex;
         }

    }

1 个答案:

答案 0 :(得分:0)

最后我找到了解决方案。实际上我创建了三个集合,一个用于已删除的元素,一个用于添加,一个用于修改。

private void TransfertToOriginal(simulation item)
    {


        try 
        {
        //Echeances that will be marked as deleted => found in "echeancier" 
        //and not in echeancierCopy

var EcheancesForDelete = item.echeancier.Except(item.echeancierCopy, new  EcheanceNumberComparer());

//Echeances that will be marked as modified => found in 2 collections
        var EcheancesForModify      = item.echeancier.Intersect(item.echeancierCopy,   new EcheanceNumberComparer());

//Echeances that will be marked as Added => found in "echeancierCopy" and not in "echeancier"
        var EcheancesForAdd         = item.echeancierCopy.Except(item.echeancier, new EcheanceNumberComparer());

//Beware to cast EcheancesForDelete collection To List otherwise an exception Collection was modified
foreach (Echeance ee in EcheancesForDelete.ToList())
        {
            base.GetCurrentUoW().Attach<Echeance>(ee);
            base.GetCurrentUoW().RegisterDeleted<Echeance>(ee);
        }

//Modification ....Don't forget ToList()
   foreach (Echeance ee in EcheancesForModify.ToList())
        {

            base.GetCurrentUoW().Attach<Echeance>(ee);
            base.GetCurrentUoW().RegisterChanged<Echeance>(ee);

        }


//New records here
        foreach (Echeance ee in EcheancesForAdd.ToList())
        {
            base.GetCurrentUoW().Attach<Echeance>(ee);
            base.GetCurrentUoW().RegisterNew<Echeance>(ee);
        }



        }
        catch (Exception ex)
        {


            _logger.LogException(ex);
            throw ex;
        }


    }

比较器如下:

public class EcheanceNumberComparer : IEqualityComparer<Echeance>
{    
    public bool Equals(Echeance x, Echeance y)
    {

        if (Object.ReferenceEquals(x, y)) return true;
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;
        return x.EchNumber == y.EchNumber;
    }



    public int GetHashCode(Echeance e)
    {
        if (Object.ReferenceEquals(e, null)) return 0;
        int hashEcheanceNumber = e.EchNumber.GetHashCode();
        return hashEcheanceNumber;
    }
}

再见。