NHibernate 坚持将对象添加到集合的顺序

发布于 2024-11-26 00:05:46 字数 1743 浏览 1 评论 0原文

我可能在这里犯了一个新手错误,但我不知道如何进行这项工作。我有两个实体 - ParentChild,其中一个 Parent 可以有多个 Children。问题似乎是,当我向父级添加新子级时,父级无法级联保存子级,因为子级实例还没有 ID。另一方面,子项无法自行持久化,因此它无法获取 ID...

我的映射:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent);
}

现在,我的数据库中可能已经有一条父记录,我想添加一条子项到其子项集合。为此,我创建了 Child 类的新实例,将子级添加到父级的 Children 属性(类型为 IList )。我还获取父记录并将子级 Parent 属性设置为父实体。

当我尝试保存它时,无论我尝试按哪个顺序执行,都会出现错误。

使用Save(p),保存父记录并希望子记录能够级联保存,我收到以下错误:

无法将 NULL 值插入表“dbo.Children”的“ChildID”列;列不允许空值。插入失败。该声明已终止。

如果我尝试相反的方法,即首先保存子项,然后将其添加到父项并保存父项,则会出现以下错误:

Application.Domain.Entities.Child 条目中的 id 为空(发生异常后不刷新会话)

我应该按什么顺序调用 parent.Children.Add(child), child. Parent = Parentsession.Save(parent)session.Save(child) 以使此工作正常吗?我的映射配置中是否缺少某些内容?

更新:我添加了.Inverse(),并尝试了以下操作但没有成功:

// First of the above errors
session.Save(child);
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);

I'm probably making a newbie mistake here, but I can't figure out how to make this work. I have two entities - Parent and Child, where one Parent can have many Children. The problem seems to be that when I add a new child to a parent, the parent can't cascade save the child, because the child instance doesn't have an ID yet. On the other hand, the child can't be persisted on its own, so it has no way of getting an ID...

My mappings:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent);
}

Now, I might already have a parent record in my database, and I want to add a child to its collection of children. To do so, I create a new instance of the Child class, add the child to the parent's Children property (of type IList<Child>). I also fetch the parent record and sets the childs Parent property to the parent entity.

When I try to save this, I get errors no matter which order I try to do it.

With Save(p), saving the parent record and hoping the child will be saved on cascade, I get the following error:

Cannot insert the value NULL into column 'ChildID', table 'dbo.Children'; column does not allow null values. INSERT fails. The statement has been terminated.

If I try the other way around, i.e. first saving the child, then adding it to the parent and saving the parent, I get the following error:

null id in Application.Domain.Entities.Child entry (don't flush the Session after an exception occurs)

In what order should I call parent.Children.Add(child), child.Parent = parent, session.Save(parent), and session.Save(child) to make this work? Is something missing in my mapping configuration?

Update: I've added .Inverse(), and tried the following without success:

// First of the above errors
session.Save(child);
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(parent);

// Second of the above errors
child.Parent = parent;
parent.Children.Add(child);
session.Save(child);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅听莫相离 2024-12-03 00:05:46

在父母一方将您的关系标记为Inverse。这会说 NHibernate 的子端管理关系:

HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad().Inverse();

这迫使您手动设置 child.Parent =parent ,但无论如何您都会这样做,所以我相信这不是问题。

默认情况下,NHibernate 假定父级有责任为子级设置外键。操作的逻辑顺序看起来像这样:

  1. 父级将被保存
  2. 子级由于级联而被保存 - 我们还没有父级 ID(至少我们不能有,我不知道为什么当我们知道时它会这样工作它也是)
  3. 子级在父级的外键中插入 null
  4. 然后成功插入父级,获取其 ID
  5. 子级更新了父级的外键。

在您的第一个场景中,它在第 3 处失败,因为您没有可为空的外键列,并且 NHibernate 不够聪明,无法找到任何解决方案。

设置 Inverse() 告诉 Parent 不要关心 Child 外键,并且您有责任正确设置 child.Parent 。在这种情况下保存时,只有 INSERT,如预期的那样,并且不会尝试在外键中设置 null

Mark your relation as Inverse on parent's side. This will say NHibernate that child's side manages the relation:

HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad().Inverse();

This forces you to set child.Parent = parent manually, but you're doing it anyway, so I believe it's not a problem.

By default, NHibernate assumes that it's parent's responsibility to set a foreign key on a child. And the logical order of operations look somehow like this:

  1. Parent is to be saved
  2. Children are saved due the cascade - we have no Parent ID yet (at least we could not have, I don't know why it works like that when we know it, too)
  3. Children are INSERTed with null in Parent's foreign key
  4. Parent is then successfully INSERTed, its ID is fetched
  5. Children have Parent's foreign key UPDATEd.

In your first scenario, it fails at no 3 as you have not nullable foreign key column and NHibernate is not smart enough to find any solution.

Setting Inverse() tells Parent to not care about Child foreign key and it's your responsibility to set child.Parent properly. On save in this case, there are only INSERTs, as expected and no tries to set null in foreign key.

饮惑 2024-12-03 00:05:46

事实证明,问题根本不在于 NHibernate,而在于我的数据库配置 - 我忘记配置 Children 表的 ID 列。一旦我指定了 ID 列,一切都会按预期工作:不需要 .Inverse(),并且我可以只保存 ParentChild 保存在级联中。

Turns out the problem wasn't with NHibernate at all, but rather with my database configuration - I had forgotten to configure the ID column of the Children table. As soon as I specified the ID column, everything worked as expected: no .Inverse() needed, and I could save just the Parent and the Child is saved on cascade.

远昼 2024-12-03 00:05:46

我缺少 Cascade.All()References。我们不应该将 Inverse() 放在 HasMany 上:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent).Cascade.All();
}

I was missing Cascade.All() with References. We shouldn't put Inverse() on HasMany:

public ParentMap()
{ 
    // ID and other properties

    HasMany(p => p.Children).Cascade.AllDeleteOrphan().Not.LazyLoad();
}

public ChildMap()
{
    // ID and other properties

    References(c => c.Parent).Cascade.All();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文