给出以下示例:
public class Parent
{
public Guid ID {get;set;}
public string Name {get;set;}
public Child Child {get;set;}
}
public class Child
{
public Guid ID {get;set;}
public string Name {get;set;}
}
我想保存一个Parent对象实例,并为其分配一个Child实例。这里的事实是:给定的子对象已存在于数据库中,
Parent p = new Parent();
p.ID = Guid.NewGuid();
// Get the Child Object
Child c = GetTheChild(...);
p.Child = c;
SaveParent ( p );
在函数Save Parent中,实现了以下代码:
public void SaveParent ( Parent p )
{
using (MyContext context = new ClinicContext())
{
context.Parents.Add( P );
context.SaveChanges();
}
}
现在问题出现了:因为这个例子中的子节点已经存在于数据库中,但是当在上下文DBSet中添加父节点时,给定的实体c也保持条目状态为“已添加”,猜猜是什么? DBContext尝试使用重复的密钥保存另一个子记录!
任何人都知道如何解决这个问题?如果实体框架可以检测到数据库中已存在的记录,我在想是否有办法将Insert转换为Update。
感谢您的帮助。
答案 0 :(得分:0)
如果您添加实体,则会添加所有相关实体。如果您附加实体,则将附加所有相关实体。在您的情况下,您想要添加父实体,然后附加子实体。您还可以尝试使用外键并添加父键,只需将外键设置为相关的子ID即可。这样您就不必将实体带到客户端来创建关系(您需要知道相关实体的密钥)。
答案 1 :(得分:0)
你是如何生孩子的?应将子项附加到您保存父项的相同上下文中。
我的猜测是你的GetTheChild函数使用了一个新的上下文 - 这意味着当你返回时,孩子是分离的,并且出于所有目的和目的,EF数字已被“添加”
正如小组所说,您可以添加一个外键,只需设置孩子的密钥而不是孩子本身,但似乎有一些设计问题需要解决。
答案 2 :(得分:0)
我猜GetTheChild()会从数据库返回一个子节点。因此,您需要做的就是在调用SaveChanges之前调用ChangeObjectState方法将子标记为Unchanged。
var osm = context.ObjectStateManager;
osm.ChangeObjectState(child, EntityState.Unchanged);