功能NHibernate级联问题 - 试图插入空ID级联、功能、问题、ID

2023-09-03 02:00:45 作者:猪是的念来过倒字名把

我有以下型号和放大器;映射(code段下文)。

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

一场比赛都必须有它(可多选)从一开始就相关的多个CompetitionAnswers。

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

在present,使用如下所示的功能NHibernate映射,当我创建一个全新的竞争对象,填充的属性,然后创建3个全新的CompetitionAnswer对象,并将它们添加到CompetitionAnswers物业(财产比赛),我希望调用保存的会话这将插入1比赛行和3 CompetitionAnswer行到数据库。

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.

然而,当我尝试调用保存的会话,它抱怨CompetitionId为空,它不能插入一个空到CompetitionAnswers表中的字段 - 但它是正确的,它不应该,我认为NHibernate的会首先创建的比赛,然后用新生成的IDENTITY值(CompetitionId)在CompetitionAnswers表?

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?

大赛(模型)

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(流利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(流利NHibernate的映射)

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

下面是我用来测试这种情况下,这会产生错误的一些示例code:

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:

不能插入NULL值成   列'CompetitionId,表   CompetitionAnswers​​;列不   允许空值。 INSERT失败。该   语句已终止。

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?

推荐答案

我是pretty的肯定,而不是100%,这个问题是逆()规范CompetitionAnswers你竞争的映射。逆()指定的子记录负责定义他们的关系到父。大多数情况下,一对多(父)的一方是一个对象图的顶和拥有与它的儿童的关系。父母有孩子,并就是否保留或送人的孩子通过的决定是父母的。然而,这并非总是如此;大学可能有学生,但它是谁拥有真正的权力来决定他们会去的学生。在这里,学生是图的顶,学校只是一个单片记录标识学生的出勤率。学生可以转移在任何时间;这是他们的决定,它并没有真正改变学校以任何有意义的方式,让学生有责任确定自己属于学校。

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.

您的情况是第一个:比赛有CompetitionAnswers,和孩子没有逻辑上有说:我属于竞争的责任;竞争,而不是拥有的答案的集合。卸下逆()指令应使NH对待比赛的对象图的顶,所以NH将插入的竞争,那么CompetitionAnswers,现在可以参考他们的父母的身份证。

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.

另一件不相关的问题,但如果你映射到一个MS SQL Server数据库,以及ID列被定义为在数据库中标识列,我指定 GeneratedBy。标识()的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.