我正在尝试熟悉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;
}
}
答案 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;
}
}
再见。