流畅的NHibernate级联问题 - 尝试插入NULL ID

时间:2011-03-08 16:30:07

标签: .net asp.net nhibernate fluent-nhibernate

我有以下型号&映射(下面的代码片段)。

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

目前,使用下面显示的Fluent NHibernate映射,当我创建一个全新的Competition对象时,填充属性,然后创建3个全新的CompetitionAnswer对象并将它们添加到CompetitionAnswers属性(竞争中的属性),我希望在会话上调用Save,它会将1个Competition行和3个CompetitionAnswer行插入到DB中。

但是,当我尝试在会话上调用Save时,它会抱怨CompetitionId为null并且无法在该字段的CompetitionAnswers表中插入null - 这是对的,但是,它不应该我假设NHibernate首先创建竞赛,然后在CompetitionAnswers表中使用新生成的IDENTITY值(CompetitionId)?

比赛(模特)

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");
}

以下是我用来测试此场景的一些示例代码,它会生成错误:

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',表格   'CompetitionAnswers';专栏没有   允许空值。 INSERT失败。该   声明已被终止。

任何人都可以详细说明为什么目前没有这个工作吗?

3 个答案:

答案 0 :(得分:22)

我很确定,而不是100%,问题是竞争中的CompetitionAnswers映射中的Inverse()规范。 Inverse()指定子记录负责定义它们与父级的关系。大多数情况下,一对多(父母)的“一”面是对象图的“顶部”,并且“拥有”与其子女的关系。父母有孩子,关于是否保留或收养孩子的决定是父母的。然而,情况并非总是如此;一所大学可能有学生,但是有能力决定他们将去哪里的学生。在这里,学生是图表的“顶部”,学校只是识别学生出勤率的单一记录。学生可以随时转学;这是他们的决定,并没有真正以任何有意义的方式改变学校,因此学生有责任将自己视为属于学校。

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

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

答案 1 :(得分:5)

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

并确保孩子除了父母在其集合中持有孩子之外还指向父母。当父级是反向时,这是必需的。

a1.Competition = c; 

数据库端的列non null是否在NH端映射为可空?

答案 2 :(得分:0)

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

我发现了NHibernate cascading save