【问题标题】:Inserting a record with a Composite Key using NHibernate fails使用 NHibernate 插入带有复合键的记录失败
【发布时间】:2019-02-22 04:08:17
【问题描述】:

我正在尝试使用部分父复合 ID 引用一些子实体。 我有一个表格定义如下:

Programs
Events
ProgramEvents

类文件:

public class Program
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IList<ProgramEvent> StartEvents { get; set; }
    public virtual IList<ProgramEvent> EndEvents { get; set; }
}

public class ProgramEvent
{
    public virtual Event Event { get; set; }
    public virtual bool Repeatable { get; set; }
    public virtual int EventOrder { get; set; }
    public virtual int EventSection { get; set; }
    public virtual Program Program { get; set; }

    public override bool Equals(object obj)
    {
        return Equals(obj as ProgramEvent);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = GetType().GetHashCode();

            hash = (hash * 31) ^ EventSection.GetHashCode();
            hash = (hash * 31) ^ EventOrder.GetHashCode();
            hash = (hash * 31) ^ Event.Id.GetHashCode();
            hash = (hash * 31) ^ Program.Id.GetHashCode();

            return hash;
        }
    }

程序类的映射包含这样的参考:

<list name="StartEvents" table="ProgramEvents" lazy="false" where="EVENT_SECTION = 1" cascade="all-delete-orphan" inverse="true">
  <key column="PROGRAM_ID" />
  <index column="EVENT_ORDER" />
  <one-to-many class="ProgramEvent"/>
</list>

程序事件类的映射:

  <class name="ProgramEvent" table="ProgramEvents">

    <composite-id>
      <key-many-to-one class="Program"  lazy="false" name="Program" column="PROGRAM_ID" />
      <key-many-to-one class="Event"  lazy="false" name="Event" column="EVENT_ID" />
      <key-property name="EventOrder" column="EVENT_ORDER" />
      <key-property name="EventSection" column="EVENT_SECTION" />
    </composite-id>

    <property name="Repeatable" column="REPEATABLE"/>

  </class>

当我尝试使用对事件表的新引用来保存程序时,我收到了这样的错误:

SqlException:无法将值 NULL 插入列“PROGRAM_ID”, 表“节目事件”;列不允许空值。 插入失败。声明已终止。

我打开 sql profiler 得到了这样的 sql:

exec sp_executesql N'INSERT INTO ProgramEvents (REPEATABLE, PROGRAM_ID、EVENT_ID、EVENT_ORDER、EVENT_SECTION)值(@p0、@p1、 @p2,@p3,@p4)',N'@p0 位,@p1 int,@p2 int,@p3 int,@p4 int',@p0=1,@p1=NULL,@p2=NULL,@p3=0,@p4=0

NHibernate 确实尝试插入空值。为什么会这样?

UPD 我尝试像这样更新程序:

    var program = ProgramDao.Current.GetById(1);

    var newEvent = EventDao.Current.GetById(4);
    var programEvent = new ProgramEvent { Event = newEvent, Repeatable = true };
    program.StartEvents.Add(programEvent);

    using (var session = SessionFactory.Current.OpenSession())
    {
        session.Evict(program);
        session.Update(program);
        session.Flush();
    }

【问题讨论】:

  • 没用。

标签: c# nhibernate


【解决方案1】:

试试这个代码:

public class ClassNameMap: ClassMap<ClassName>
{
    public ClassNameMap()
    {
        CompositeId().
            .KeyReference(x => x.A, "A")
            .KeyReference(x => x.B, "B");
    }
}

【讨论】:

  • 但是我已经在 ProgramEvent 映射文件中声明了复合 ID。
【解决方案2】:

您必须将 programEvent.Program 设置为指向该程序。当您指定 inverse=true 时,包含的类有责任维护对 Program 的引用。

另外,我会避免驱逐和更新。在常见的程序结构中不应该是必需的。但是您的示例代码很奇怪……您应该加载 Program 实例并在一个会话中进行更改。 (这不是必需的。有一些代码结构可以以其他方式执行此操作,但除非您绝对确定必须以另一种方式执行此操作,否则在单个会话中执行加载、修改和持久(刷新)通常要容易得多。您真的( !) 还应该打开一个事务以确保可靠运行。

【讨论】:

  • 我已经尝试设置 programEvent.Program 但它没有帮助。似乎 nhibernate 在插入过程中只是忽略了我模型中的所有值。顺便说一下,更新操作做得很好。这只是示例代码,我在单元测试中使用它。
猜你喜欢
  • 2010-11-02
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
相关资源
最近更新 更多