[英]Entity framework 6 Code First one-to-many optional relationship remove child issue
I'm currently working on a small application with WPF, EF6 and SqlServer 2012. I have two entities "Region" and "BctGouvernorats" associated with an optional one to many relationship. 我目前正在使用WPF,EF6和SqlServer 2012开发一个小应用程序。我有两个实体“Region”和“BctGouvernorats”与可选的一对多关系相关联。
My problem is : When I remove a child from the relationship (BctGouvernorat), it still appears in the collection related to the parent (Region). 我的问题是:当我从关系中删除一个孩子(BctGouvernorat)时,它仍然出现在与父(Region)相关的集合中。 here's the code: 这是代码:
//Entities
public partial class BctGouvernorat
{
public long GovId { get; set; }
public string Libelle { get; set; }
public long UserId { get; set; }
public Nullable<long> RegionId { get; set; }
public virtual Region Region { get; set; }
}
public partial class Region
{
public long RegionId { get; set; }
public string Libelle { get; set; }
public long GroupeNumber { get; set; }
public byte Bonus { get; set; }
public long UserId { get; set; }
public virtual RegionsGroupes GroupeRegions { get; set; }
public virtual ICollection<BctGouvernorat> Gouvernorats { get; set; }
public Region()
{
Libelle = "New region";
GroupeNumber = 0;
this. Gouvernorats = new HashSet<BctGouvernorat>() ;
}
//C# code for "Modify" Method
public void Modify(Region r, List<BctGouvernorat> _ToUnlink, List<BctGouvernorat> _ToLink)
{
//Below the code for unlink child from parent
if (_ToUnlink.Count > 0)
{
r.Gouvernorats.ToList().All(xx =>
{
if (_ToUnlink.Contains(xx))
{
xx.RegionId = null;
xx.Region = null;
}
return true;
}
);
}
//Here the code for link child to the parent
_ToLink.All(xx =>
{
xx.RegionId = r.RegionId;
xx.Region = r;
r.Gouvernorats.Add(xx);
return true;
});
//Mark Childs collection as modified
r.Gouvernorats.All(xx =>
{
_uow.GetEntry<BctGouvernorat>(xx).State = EntityState.Modified;
return true;
});
base.Modify(r);
}
actually the previous method is included in a «RegionRepository» which inherits from a base class Repository. 实际上,前一个方法包含在一个«RegionRepository»中,它继承自基类Repository。 The code of base.Modify() is as follows : base.Modify()的代码如下:
//Method Modify from RegionRepository
public void Modify(T item)
{
_uow.RegisterChanged(item);
_uow.Commit();
}
And The "Modify" Method uses services of a unit of work "_uow" that save data to sqlserver database. 并且“修改”方法使用将数据保存到sqlserver数据库的工作单元“_uow”的服务。 Here the code : 这里的代码:
//***************************
//_uow is a unit of work
//*****************************
public void RegisterChanged<T>(T item) where T : class
{
base.Entry<T>(item).State = System.Data.Entity.EntityState.Modified;
}
public void Commit()
{
try
{
base.SaveChanges();
}
catch (DbUpdateException e)
{
var innerEx = e.InnerException;
while (innerEx.InnerException != null)
innerEx = innerEx.InnerException;
throw new Exception(innerEx.Message);
}
catch (DbEntityValidationException e)
{
var sb = new StringBuilder();
foreach (var entry in e.EntityValidationErrors)
{
foreach (var error in entry.ValidationErrors)
{
sb.AppendLine(string.Format("{0}-{1}-{2}",
entry.Entry.Entity,
error.PropertyName,
error.ErrorMessage
));
}
}
throw new Exception(sb.ToString());
}
}
And mappings : 和映射:
//Mapping of BctGouvernorat entity
public BctGouvernoratMapping()
{
this.ToTable("BctGouvernorat");
this.HasKey(t => t.GovId);
this.Property(t => t.GovId);
this.HasOptional(t => t.Region)
.WithMany(t => t.Gouvernorats)
.HasForeignKey(d => d.RegionId)
.WillCascadeOnDelete(false);
}
//Mapping of Region entity
public RegionMapping()
{
this.ToTable("Region");
this.HasKey(t => t.RegionId);
this.Property(t => t.RegionId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
and finally viewmodel that calls the code above 最后调用上面代码的viewmodel
private void SaveRegion()
{
List<BctGouvernorat> _GovToLink = null;
//The following method checks and returns (Added, Deleted, Modified BctGouvernorat)
List<BctGouvernorat> _GovToUnlink = CheckGouvernoratsListStatus(out _GovToLink);
ILogger _currentLog = (Application.Current as App).GetCurrentLogger();
using (UnitOfWork cx = new UnitOfWork(_currentLog))
{
RegionRepository _regionRepository = new RegionRepository(cx, _currentLog);
IRegionManagementService rms = new RegionManagementService(_currentLog, _regionRepository);
if (CurrentRegion.RegionId == 0)
{
CurrentRegion.UserId = Session.GetConnectedUser().UserId;
rms.AddRegion(CurrentRegion);
}
else
rms.ModifyRegion(CurrentRegion, _GovToUnlink,_GovToLink);
}
}
//The following method checks and returns (Added, Deleted, Modified BctGouvernorat)
private List<BctGouvernorat> CheckGouvernoratsListStatus(out List<BctGouvernorat> _ToLink)
{
List<BctGouvernorat> AddedGouvernorats = GouvernoratsRegion.Except<BctGouvernorat>(CurrentRegion.Gouvernorats,
new GouvernoratComparer()).ToList();
_ToLink = AddedGouvernorats;
List<BctGouvernorat> DeletedGouvernorats = CurrentRegion.Gouvernorats.Except<BctGouvernorat>(GouvernoratsRegion,
new GouvernoratComparer()).ToList();
return DeletedGouvernorats;
}
public void ModifyRegion(Region r, List<BctGouvernorat> _ToUnlik, List<BctGouvernorat> _ToLink)
{
_regionRepository.Modify(r, _ToUnlik, _ToLink);
}
The "GouvernoratsRegion" is an observablecollection bound to a datagrid that i edit to add or remove BCTgouvernorat Rows to the region “GouvernoratsRegion”是一个observablecollection绑定到一个数据网格,我编辑,以添加或删除BCTgouvernorat行到该区域
Finaly i found a solution. 最后,我找到了解决方案。 The trick is that in this situation : an optional Association one to many with a foreign key : When i want to remove items from childs collection, the parent entity must be first marked as modified, but when i want to link new items to childs collection, the, the parent must be marked after. 诀窍在于:在这种情况下:使用外键可选的一对多关联:当我想从子集合中删除项目时,必须首先将父实体标记为已修改,但是当我想将新项目链接到子集合时,必须在之后标记父母。 here's the code the method modify become as follows : 这里修改方法的代码如下:
public void Modify(Region r, List<BctGouvernorat> _ToUnlink, List<BctGouvernorat> _ToLink)
{
_ToLink.All(xx =>
{
xx.RegionId = r.RegionId;
xx.Region = r;
_uow.GetEntry<BctGouvernorat>(xx).State = EntityState.Modified;
r.Gouvernorats.Add(xx);
return true;
});
//The parent entity must be marked as modified here :
// after adding new items but before removing items from collection
_uow.GetEntry<Region>(r).State = EntityState.Modified;
if (_ToUnlink.Count > 0)
{
r.Gouvernorats.ToList().All(xx =>
{
if (_ToUnlink.Contains(xx))
{
xx.RegionId = null;
xx.Region = null;
}
return true;
}
);
}
base.Modify(r);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.