破坏 POCO 关系
我在破坏两个实体之间的关系时遇到问题。假设我们有一个 Child
实体,它属于一个 Parent
,一个 Parent
拥有许多 Child
实体。现在,在我的前端,用户可以选择一个单选按钮来选择 Child
属于哪个 Parent
,或者他们可以选择“None”。我遇到的问题是,当我编辑 Child
记录并选择“无”时,它似乎并没有破坏现有关系。
在我的业务逻辑中,我正在执行以下操作:
child.Parent = parentRepository.Find(command.ParentID);
如果没有记录与传入的 ID 匹配,则存储库方法返回 null,并且选择“无”会给出 0 ID,但当我调试并跨过此行时,Child.Parent 仍然有一个引用先前选择的父实体。事实上,甚至显式设置 Child.Parent = null;似乎没有破坏链接。
更让我困惑的是,这不是一致的行为。时不时地,相同的代码确实会破坏关系并将Child.Parent设置为null!有人可以指出我正确的方向吗?
更新
我更新了代码以确保存储库返回 null。
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
child.parent = null;
else
child.parent = parent;
调试显示行 child.parent = null;
is 正在执行,但是当我在该行之后检查 child.parent
时,它仍然显示对先前引用的 Parent
对象的引用。但时不时地,它会被正确设置为 null。此版本有效:
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
{
child.parent = null;
child.parent = null;
}
else
child.parent = parent;
为什么我必须将其设置为 null 两次才能获得一致的行为?我是否必须以某种方式显式声明 Parent
在 Child
实体上可为空?
I'm experiencing a problem in breaking a relationship bteween two entities. Let's say we have a Child
entity which belongs to one Parent
, a Parent
has many Child
entities. Now in my front end a user can select a radio button to choose which Parent
the Child
belongs to or they can choose "None". The trouble I'm having is that when I edit a Child
record and select "None", it doesn't seem to break an existing relationship.
In my business logic I am doing the following:
child.Parent = parentRepository.Find(command.ParentID);
The repository method returns null if no record matches the passed in ID, and selecting "None" gives an ID of 0 yet when I debug and step over this line, Child.Parent still has a reference to the previously chosen Parent entity. In fact, even explicitly setting Child.Parent = null; doesn't seem to break the link.
To add to my confusion, this isn't consistant behaviour. Every now and then the same code does break the relationship and set Child.Parent to null! Can someone please point me in the right direction?
UPDATE
I updated my code to ensure that the repo is returning null.
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
child.parent = null;
else
child.parent = parent;
Debugging shows that the line child.parent = null;
is being executed, yet when I check child.parent
after this line, it still shows a reference to the previously referenced Parent
object. But every now and then, it is correctly setting to null. This version works:
Parent parent = parentRepository.Find(command.ParentID);
if (parent == null)
{
child.parent = null;
child.parent = null;
}
else
child.parent = parent;
Why do I have to set it to null twice to get consistant behaviour? Do I have to explicitly declare that Parent
is nullable on the Child
entity somehow?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的,您确实需要声明父级可为空。
如果您在子项上公开外键属性,则它必须可为空。因此,如果您的孩子有 ParentId 属性,它应该如下所示:
如果您使用流畅的 API,您可以像这样告诉 EF 父级可为空:
或者像这样,如果您从主体端而不是从主体端声明关系依赖端:
奇怪的是child.Parent需要设置为null两次。您是否尝试过单步查看代码以了解原因?您还可以对 Parent 属性尝试此操作,以准确了解发生了什么:
这是您实际上可以进入的代码,以确保私有字段设置为 null。
对评论的回应
听起来确实存在延迟加载的问题。试试这个。
在存储库 Find 方法中,立即加载父级。你可以用这样的方法来做到这一点:
这将使 child.Parent 已经加载到上下文中,并且设置为 null 一次就足够了。
Yes, you do need to declare that the parent is nullable.
If you expose a foreign key property on the child, it has to be nullable. So if your child has a ParentId property, it should look like this:
If you are using the fluent API, you can tell EF that the parent is nullable like this:
Or like this, if you declare the relationship from the principal end rather than the dependent end:
It is strange that the child.Parent needs to be set to null twice. Have you tried stepping into the code to see why? You could also try this for your Parent property, to see exactly what is going on:
This is code you can actually step into, to make sure that the private field is being set to null.
Response to comment
It does sound like there is an issue with lazy loading going on. Try this.
In your repository Find method, eager load the parent. You can do that with something like this:
This would make child.Parent already loaded on the context, and setting to null once should suffice.