C# 在一对多关系中管理孤儿
使用实体框架,我在两个表之间建立了父子关系。我正在从联机源检索数据并在本地保存数据 随着父母寿命的延长,孩子的列表在各个方面都会发生变化。可以添加、删除或编辑子项 第1步: 在我的场景中,我得到了一个有1-2个孩子的父母。我使用以下方法创建父/子对象:C# 在一对多关系中管理孤儿,c#,entity-framework,C#,Entity Framework,使用实体框架,我在两个表之间建立了父子关系。我正在从联机源检索数据并在本地保存数据 随着父母寿命的延长,孩子的列表在各个方面都会发生变化。可以添加、删除或编辑子项 第1步: 在我的场景中,我得到了一个有1-2个孩子的父母。我使用以下方法创建父/子对象: Parent p = new Parent(); Child c1 = new Child (); c1.Name = "Test1"; Child c2 = new Child (); c2.Name = "Test2"; p.Child
Parent p = new Parent();
Child c1 = new Child ();
c1.Name = "Test1";
Child c2 = new Child ();
c2.Name = "Test2";
p.Children.Add(c1);
p.Children.Add(c2);
context.AddToParents(p);
context.SaveChanges();
第二步:
下次我更新child时,2已经不存在了。在本例中,我查询了我的在线来源,并收到了一个不包含子项“Test2”的子项列表。我通过使用linq从parent.Children列表中删除子项来模拟这种情况(因为代码是不可复制的)
子项定义为(在父项中):
发生这种情况时,不会从表中删除子项,但父项为空
第三步:
稍后,当我从在线来源获得更新时,child#2现在又是其中一个孩子。当我将该记录添加回时,我得到一个密钥冲突,因为该记录仍在表中
var parent = (from p in context.Parents
where p.Name == "Parent"
select p).FirstOrDefault();
Child child = new Child();
child.Name = "Test2";
parent.Children.Add(child);
context.SaveChanges();
我得到这个错误:
违反主键约束“PK_Slave”。无法在对象“dbo.Child”中插入重复键。重复键值为(Test2)。\r\n语句已终止
我猜我需要在使用新数据更新父记录后从表中删除孤立子记录(在步骤2中),或者-首先使用指向父记录的空指针检查现有子记录,并重用该记录,而不是添加新的子记录。或者两者兼而有之
有更好的设计模式吗?下午我一直在看,答案是避开我。首先,请注意,您在问题中提到的从不同的源获取数据,然后将其投影到在实体框架上下文中添加/创建的新实例的场景并没有在您提供的代码片段中表示:您向我们提供了反映您工作的sudo代码。虽然我不认为这是步骤1的问题,但我感兴趣的是如何实现步骤2,因为它涉及实例\实体。
c2
是否是从上下文中查询的Child
的实例?Children
aHashTable
onParent
类型,并且p
是该上下文的实例\实体吗?@BrettCaswell-实际上,这不是伪代码。我建立了两个超级简化的测试表,这些代码取自我一直在做的测试。我将编辑上面的帖子来回答你的问题。谢谢你更新你的问题。。实际上,我可以看到,在不删除子记录的情况下,人们可能希望删除记录之间的关系,因此我倾向于相信,删除父记录范围内的子记录的行为就代表了这一点;其中,从context.Children
中删除实例意味着要删除记录本身。不过,我确实相信有一种DbConfiguration
或其他方式来指示这种行为。请看,自从我经常使用EF(这是edmx的Db首款)以来,EF的设计有了一些变化。。。您是否从数据库中生成了这些实体\模型?您是否尝试过从父级获取实例(基本上是延迟加载它们)并删除这些实例并保存它们。是否parent.Children.Where(c=>c.Name==childNameToRemove).FirstOrDefault()
返回实例或某个IKeyLookup类型?。。另外,我建议您添加一个DbConfiguration拦截器,该拦截器将输出到调试控制台,以便您可以在首先执行SaveChanges
时看到表达式输出,请注意,您在问题中提到的从不同的源获取数据,然后将其投影到在实体框架上下文中添加/创建的新实例的场景并没有在您提供的代码片段中表示:您向我们提供了反映您工作的sudo代码。虽然我不认为这是步骤1的问题,但我感兴趣的是如何实现步骤2,因为它涉及实例\实体。c2
是否是从上下文中查询的Child
的实例?Children
aHashTable
onParent
类型,并且p
是该上下文的实例\实体吗?@BrettCaswell-实际上,这不是伪代码。我建立了两个超级简化的测试表,这些代码取自我一直在做的测试。我将编辑我的文章来回答你的问题。谢谢你的问题更新。。实际上,我可以看到,在不删除子记录的情况下,人们可能希望删除记录之间的关系,因此我倾向于相信,删除父记录范围内的子记录的行为就代表了这一点;其中,从context.Children
中删除实例意味着要删除记录本身。不过,我确实相信有一种DbConfiguration
或其他方式来指示这种行为。请看,自从我经常使用EF(这是edmx的Db首款)以来,EF的设计有了一些变化。。。您是否从数据库中生成了这些实体\模型?您是否尝试过从父级获取实例(基本上是延迟加载它们)并删除这些实例并保存它们。是否parent.Children.Where(c=>c.Name==childNameToRemove).FirstOrDefault()
返回实例或某个IKeyLookup类型?。。另外,我建议您添加一个DbConfiguration拦截器,该拦截器输出到调试控制台,以便在执行SaveChanges
var parent = (from p in context.Parents
where p.Name == "Parent"
select p).FirstOrDefault();
string childNameToRemove = "Test2";
var child = (from c in context.Children
where c.Name == childNameToRemove
select c).FirstOrDefault();
parent.Children.Remove(child);
context.SaveChanges();
var parent = (from p in context.Parents
where p.Name == "Parent"
select p).FirstOrDefault();
Child child = new Child();
child.Name = "Test2";
parent.Children.Add(child);
context.SaveChanges();