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

C# EF 6:当我将元素标记为已删除时,集合长度减少,c#,wpf,entity-framework,C#,Wpf,Entity Framework,我试图先熟悉EF6代码、WPF和C。我使用了两个与一对多关系相关的实体 «模拟»是父级 «echeance»是孩子 public partial class simulation : INotifyPropertyChanged { public long SimulationId { get; set; } ... ... ... public virtual ICollection<Echeance>

我试图先熟悉EF6代码、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; }
    ...
    ...
    ...
}
实际上,当我想修改«simulation»时,首先我从数据库中读取它,然后将«echeancier»集合克隆到«echeanceCopy»列表中,然后将«echeanceCopy»数据绑定到WPF数据网格中,这样我就可以在数据网格单元中以交互方式进行更改。当我要保存模拟时: 有两种情况:

1新模拟:我将«echeanceCopy»Lits转换为«echeancier»集合并保存。它很好用

2旧模拟:我将«echeanceCopy»Lits转换为«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;
         }

    }

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

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;
    }
}

再见。

如果删除某个元素或将其标记为已删除,则该元素将从集合中删除。如果已删除,是吗?。但你为什么要这么做?如果不想保存,请不要调用SaveChanges DbContext已是UnitOfWork。我想保存更改,所以我使用TransferToOriginal方法准备eCeancier集合以将其保存到数据库中。实际上,我后来也使用了SaveChanges,但我在代码中没有提到它。关于你的问题,我为什么要这样做?否则,我如何保存更改?您说如果我将集合的某个元素标记为已删除,它将从此集合中删除。这种行为正常吗?如果是,我不明白EF如何知道它必须从数据库中删除的记录(如果它们已经从原始集合中删除)?EF将为您处理所有必要的事情-您不必包装添加、更改和删除。EF有一个ChangeTracker,它会看到,如果你做了什么。谢谢你抱怨85,看来我有很多工作要做