Fluent NHibernate 级联问题 - 尝试插入 NULL ID

发布于 2024-10-21 00:58:58 字数 2320 浏览 1 评论 0原文

我有以下型号和映射(下面进一步的代码片段)。

一项竞赛从一开始就必须有多个与之关联的竞赛答案(多项选择)。

目前,使用如下所示的 Fluent NHibernate 映射,当我创建一个全新的 Comparison 对象,填充属性,然后创建 3 个全新的 ComparisonAnswer 对象并将它们添加到 CompetitionAnswers 属性(Competition 上的属性)时,我希望调用 Save在将 1 个竞赛行和 3 个竞赛答案行插入数据库的会话中。

但是,当我尝试在会话中调用 Save 时,它​​会抱怨 CompetitionId 为空,并且无法将 null 插入到该字段的 ComparisonAnswers 表中 - 这是正确的,但它不应该,但是,我认为NHibernate会首先创建Competition,然后在CompetitionAnswers表中使用新生成的IDENTITY值(CompetitionId)?

Competition(模型)

public virtual int CompetitionId { get; private set; }
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual IList<CompetitionAnswer> CompetitionAnswers { get; set; }

CompetitionAnswer(模型)

public virtual int CompetitionAnswerId { get; set; }
public virtual string Answer { get; set; }
public virtual Competition Competition { get; set; }

CompetitionMap(Fluent NHibernate 映射)

public CompetitionMap()
{
    Id(x => x.CompetitionId)
        .GeneratedBy.Native();
    Map(x => x.Title);
    Map(x => x.Description);
    HasMany(x => x.CompetitionAnswers)
        .Cascade.AllDeleteOrphan()
        .KeyColumn("CompetitionId")
        .Inverse();
    Table("Competitions");
}

CompetitionAnswerMap(Fluent NHibernate 映射)

public CompetitionAnswerMap()
{
    Id(x => x.CompetitionAnswerId)
        .GeneratedBy.Native();
    Map(x => x.Answer);
    References(x => x.Competition)
        .Column("CompetitionId");
    Table("CompetitionAnswers");
}

这里是我用来测试此场景的一些示例代码会生成错误:

Competition c = new Competition();

c.Description = "Description";
c.Title = "Title";

CompetitionAnswer a1 = new CompetitionAnswer { Answer = "Answer 1" };
CompetitionAnswer a2 = new CompetitionAnswer { Answer = "Answer 2" };
CompetitionAnswer a3 = new CompetitionAnswer { Answer = "Answer 3" };

c.CompetitionAnswers.Add(a1);
c.CompetitionAnswers.Add(a2);
c.CompetitionAnswers.Add(a3);

session.Save(c);

尝试保存时我收到的确切错误是:

无法将 NULL 值插入 列“CompetitionId”,表 '竞赛答案';列没有 允许空值。插入失败。这 声明已终止。

任何人都可以解释为什么这目前不起作用吗?

I have the following models & mappings (code snippets further below).

One Competition has to have multiple CompetitionAnswers associated with it (multiple choice) from the outset.

At present, using the Fluent NHibernate mappings shown below, when I create a brand new Competition object, populate the properties, then create 3 brand new CompetitionAnswer objects and add them to the CompetitionAnswers property (property on Competition), I would expect to call Save on the session which would INSERT the 1 Competition row and 3 CompetitionAnswer rows to the DB.

However, as soon as I try to call Save on the session, it complains that CompetitionId is null and it can't insert a null into the CompetitionAnswers table for that field - which is right, it shouldn't, however, I assumed that the NHibernate would first create the Competition, then use the newly generated IDENTITY value (CompetitionId) in the CompetitionAnswers table?

Competition (Model)

public virtual int CompetitionId { get; private set; }
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual IList<CompetitionAnswer> CompetitionAnswers { get; set; }

CompetitionAnswer (Model)

public virtual int CompetitionAnswerId { get; set; }
public virtual string Answer { get; set; }
public virtual Competition Competition { get; set; }

CompetitionMap (Fluent NHibernate Mapping)

public CompetitionMap()
{
    Id(x => x.CompetitionId)
        .GeneratedBy.Native();
    Map(x => x.Title);
    Map(x => x.Description);
    HasMany(x => x.CompetitionAnswers)
        .Cascade.AllDeleteOrphan()
        .KeyColumn("CompetitionId")
        .Inverse();
    Table("Competitions");
}

CompetitionAnswerMap (Fluent NHibernate Mapping)

public CompetitionAnswerMap()
{
    Id(x => x.CompetitionAnswerId)
        .GeneratedBy.Native();
    Map(x => x.Answer);
    References(x => x.Competition)
        .Column("CompetitionId");
    Table("CompetitionAnswers");
}

Here is some sample code that I've used to test this scenario, which generates the error:

Competition c = new Competition();

c.Description = "Description";
c.Title = "Title";

CompetitionAnswer a1 = new CompetitionAnswer { Answer = "Answer 1" };
CompetitionAnswer a2 = new CompetitionAnswer { Answer = "Answer 2" };
CompetitionAnswer a3 = new CompetitionAnswer { Answer = "Answer 3" };

c.CompetitionAnswers.Add(a1);
c.CompetitionAnswers.Add(a2);
c.CompetitionAnswers.Add(a3);

session.Save(c);

The exact error that I get as soon as it tries to Save is:

Cannot insert the value NULL into
column 'CompetitionId', table
'CompetitionAnswers'; column does not
allow nulls. INSERT fails. The
statement has been terminated.

Can anyone please shed any light on why this isn't currently working?

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

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

发布评论

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

评论(3

笑,眼淚并存 2024-10-28 00:58:58

我非常确定(不是 100%),问题是您的 CompetitionAnswers 映射到竞赛中的 Inverse() 规范。 Inverse() 指定子记录负责定义它们与父记录的关系。大多数情况下,一对多的“一”侧(父级)是对象图的“顶部”,并且“拥有”与其子级的关系。父母有孩子,保留孩子还是送人收养的决定权在于父母。然而,情况并非总是如此。一所大学可能有学生,但真正决定他们去往何处的是学生。在这里,学生是图表的“顶部”,而学校只是识别学生出勤情况的整体记录。学生可以随时转学;这是他们的决定,并且不会以任何有意义的方式真正改变学校,因此学生有责任表明自己属于学校。

你的情况是第一种:竞赛有竞赛答案,孩子逻辑上没有责任说“我属于竞赛”;相反,竞赛“拥有”其答案集合。删除 Inverse() 指令应该使 NH 将“竞争”视为对象图的“顶部”,因此 NH 将插入“竞争”,然后是“竞争答案”,现在可以引用其父级的 ID。

另一件事与问题无关,但如果您映射到 MS SQL Server 数据库,并且 ID 列被定义为数据库中的标识列,我会指定 GenerateBy.Identity() 用于 ID 列。 Native() 应该最终使用 Identity,但它也会检查 HiLo 或 Sequence 方法是否可用。

I'm pretty sure, not 100%, that the problem is the Inverse() specification in your mapping of CompetitionAnswers on Competition. Inverse() specifies that the child records are responsible for defining their relationship to the parent. Most often, the "one" side of a one-to-many (the parent) is the "top" of an object graph and "owns" the relationship with its children. Parents have children, and the decision regarding whether to keep or give away the child for adoption is the parent's. However, this isn't always the case; a college may have students, but it's the students who have the real power to decide where they will go. Here, the Student is the "top" of the graph, and the School is just a monolithic record identifying the Student's attendance. The Student can transfer at any time; it's their decision, and it doesn't really change the School in any meaningful way, so the Students are responsible for identifying themselves as belonging to the School.

Your case is the first one: Competitions have CompetitionAnswers, and the child doesn't logically have the responsibility of saying "I belong to a Competition"; the Competition instead "owns" its collection of answers. Removing the Inverse() instruction should make NH treat Competition as the "top" of the object graph, so NH will insert the Competition, then the CompetitionAnswers, which can now reference their parent's ID.

Another thing not related to the problem, but if you're mapping to an MS SQL Server database, and the ID column is defined as an identity column in the DB, I'd specify GeneratedBy.Identity() for the ID columns. Native() SHOULD end up using Identity, but it will also check to see if HiLo or Sequence methods are available.

如果没有 2024-10-28 00:58:58
References(x => x.Competition)
    .Column("CompetitionId")
    .Not.Nullable(); //add this

并确保除了父级将子级保存在其集合中之外,子级还指向父级。当父项是逆时,这是必需的。

a1.Competition = c; 

该列在数据库端是否非空,但在 NH 端映射为可为空?

References(x => x.Competition)
    .Column("CompetitionId")
    .Not.Nullable(); //add this

and also make sure the child points to the parent in addition to the parent holding the child in it's collection. This is required when the parent is inverse.

a1.Competition = c; 

Was that column non null on database side but mapped as nullable on NH side?

满意归宿 2024-10-28 00:58:58

你的映射没有任何问题。问题可能出在您的数据库上。如果您使用 Identity 列作为主键,则应将 ComparisonId 列设置为可为空。当您保存了一个带有子对象的全新对象时,NHibernate 的工作方式是插入父对象和子对象。然后它使用新的父对象 ID 更新子对象外键。

我发现这个 NHibernate 级联保存

There is nothing wrong with your mappings. The problem is likely with your database. If you're using Identity columns for your primary keys, the CompetitionId column should be set to nullable. The way NHibernate works when you have a brand new object with children that is saved, is it inserts the parent object and the child objects. Then it updates the child object foreign keys with the new parent object id.

I found this NHibernate cascading save

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