我在打破两个实体之间的关系方面遇到了问题。假设我们有Child
个实体,属于一个Parent
,Parent
有许多Child
个实体。现在,在我的前端,用户可以选择一个单选按钮来选择Parent
Child
所属的Child
,或者他们可以选择“无”。我遇到的麻烦是,当我编辑child.Parent = parentRepository.Find(command.ParentID);
记录并选择“无”时,它似乎不会破坏现有的关系。
在我的业务逻辑中,我正在做以下事情:
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
child.parent = null;
else
child.parent = parent;
如果没有记录与传入的ID匹配,则存储库方法返回null,选择“None”时ID为0但是当我调试并跳过此行时,Child.Parent仍然具有对先前选择的Parent实体的引用。实际上,甚至明确设置Child.Parent = null;似乎没有打破链接。
为了增加我的困惑,这不是一致的行为。偶尔会有相同的代码 打破关系并将Child.Parent设置为null!有人可以指出我正确的方向吗?
更新
我更新了我的代码,以确保repo返回null。
child.parent = null;
调试显示行child.parent
正在执行,但当我在此行后检查Parent
时,它仍显示对先前引用的{{1}的引用对象。但是不时地,它正确地设置为null。这个版本有效:
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
{
child.parent = null;
child.parent = null;
}
else
child.parent = parent;
为什么我必须将其设置为null两次才能获得一致的行为?我是否必须以某种方式明确声明Parent
实体上Child
可以为空?
答案 0 :(得分:1)
是的,您需要声明父级可以为空。
如果在子项上公开外键属性,则必须可以为空。因此,如果您的孩子有ParentId属性,它应该如下所示:
public int? ParentId { get; set; }
public virtual Parent { get; set; }
如果您使用的是流畅的API,您可以告诉EF父级可以为空:
modelBuilder.Entity<Child>.HasOptional(d => d.Parent).WithMany(p => p.Children);
或者像这样,如果你从主要结束而不是从属结束声明关系:
modelBuilder.Entity<Parent>.HasMany(p => p.Children).WithOptional(d => d.Parent);
奇怪的是,child.Parent需要设置为null两次。您是否尝试过使用代码来查看原因?您也可以尝试使用您的Parent属性,以确切了解正在发生的事情:
private Parent _parent;
public virtual Parent
{
get { return _parent; }
set { _parent = value; }
}
这是您可以实际进入的代码,以确保将私有字段设置为null。
对评论的回应
听起来确实存在延迟加载的问题。试试这个。
在您的存储库查找方法中,急切加载父级。你可以这样做:
context.Children.Include(c => c.Parent).Find(id);
这会使child.Parent已经加载到上下文中,并且设置为null就足够了。