这不是我第一次遇到这个实体框架的问题,即更新2个对象,这些对象的列表中包含具有相同子对象的子对象。
此示例的典型结构是父对象,其中包含每个都有标记列表的子对象列表。即:
class Parent{
public virtual ICollection<Child> Childs{get ;set;}
}
class Child {
public virtual IColletion<Tag> Tags{get; set;}
}
class Tag{
public int Id {get; set;}
public string Text {get; set;}
}
当尝试在同一次运行中更新父对象及其子对象时,我似乎无法找到令人满意的解决方案来向实体框架说实体Tag可以复制。
我大部分时间都遵循这个结构来更新实体框架中有孩子的父母。 How to add/update child entities when updating a parent entity in EF
为了解决这个问题,我曾经对连接表Tag_To_Childs
进行硬编码,并且只使用标记对象的id,这样实体框架就不会在重复的密钥问题中运行。无论如何,我很高兴知道是否有人知道这个问题更优雅的解决方案。
以下是我实际更新子对象和标签Lists
的方法 public async Task<List<Child>> updateChilds(Parent entry, Parent existingParent)
// entry being the new version and existingParent the tracked Db version
{
if (existingParent != null)
{
// Delete children
foreach (var existingChild in existingParent.Childs.ToList())
{
if (!entry.Charts.Any(c => c.ChildId== existingChild.ChildId))
_context.Childs.Remove(existingChild);
}
// Update and Insert children
foreach (var childentry in entry.Childs)
{
var existingChild = existingParent.Childs
.Where(c => c.ChildId== childentry.ChildId)
.SingleOrDefault();
if (existingChild != null)
// Update child
{
await updateChildTags(existingChild, childentry);
_context.Entry(existingChild).CurrentValues.SetValues(childentry);
}
else
{
// Insert child
var newChild = new Chart
{
Title = childentry.Title,
Order = childentry.Order
};
newChild = await updateChildTags(newChild, childentry);
existingParent.Childs.Add(newChild);
}
}
await _context.SaveChangesAsync();
}
return existingParent.Childs.ToList();
}
public async Task<Child> updateChartTypeQuestions(Child realBlock, Child entry)
{
//delete bad tags
List<Tag> toRemove = new List<Tag>();
foreach (var existingChild in realBlock.Tags.ToList())
{
if (!entry.Tags.Any(c => c.TagId== existingChild.TagId))
toRemove.Add(existingChild);
}
//add new ones
foreach (var toAdd in entry.Tags.ToList())
{
if (!realBlock.Tags.Any(c => c.TagId== toAdd.TagId))
{
Tag tag = await _context.Tags.FirstOrDefaultAsync(c => c.TagId == toAdd.TagId);
realBlock.Tags.Add(tag);
}
}
foreach (var toR in toRemove)
{
realBlock.Tags.Remove(toR);
}
//the save change is called by parent function
return realBlock;
}
此代码的问题是,如果2个子项具有相同的标记,则只会正确更新第二个子项,并且将从第一个子对象中删除该标记。