【问题标题】:NHibernate Optional Join generates insert instead of updateNHibernate Optional Join 生成插入而不是更新
【发布时间】:2015-05-15 03:12:49
【问题描述】:

我们目前正在使用 NHibernate 来支持灵活的实体模型。系统字段存储在一个表中,动态字段存储在扩展表中。这些表共享相同的主键。

我们使用 JOIN 组件来映射扩展表中的字典。 JOIN 组件被映射为可选,但出现以下错误:

  1. 创建一个没有动态属性的新实体。 Hibernate 在第二个表中存储了一条空记录 - 除了外键/主键之外,所有列都存储为空。

  2. 加载创建的记录并设置动态字段。

  3. 保存更新的记录会导致错误。 NHibernate 将发出新的插入而不是更新语句。

目前 Nhibernate 中存在一个可能与此有关的错误: https://nhibernate.jira.com/browse/NH-2876

我想知道目前是否有解决此 NHibernate Core 错误的方法,或者是否有人有解决方法?

谢谢!

【问题讨论】:

    标签: nhibernate fluent-nhibernate nhibernate-mapping


    【解决方案1】:

    我能够通过使用映射到指向组件上的 id 的函数来使代码工作:

    <hibernate-mapping
    xmlns="urn:nhibernate-mapping-2.2"
    assembly="NHibernate.Test"
    namespace="NHibernate.Test.NHSpecificTest.NH2876"
    default-lazy="false">
    
    <class name="Customer">
        <id name="Id">
            <generator class="guid" />
        </id>
        <property name="Name" column="Name" />
        <join table="CustomerData" optional="true">
            <key column="CustomerId" unique="true" />
            <component name="ExtendedData">
                <property name="CustomerId" formula="[CustomerId]" insert="false" update="false" />
                <property name="SomeData" />
            </component>
        </join>
    </class>
    

    这也需要将 CustomerId 属性添加到组件类中。

    发生这种情况的原因是当 NHibernate 拉取现有记录时,如果没有非空值,它不会填充相关组件。因此,当它在 AbstractEntityPersister 中调用 UpdateOrInsert 时检查“旧值”时,它只看到组件属性的空对象,因此认为它是一个插入。当表中没有记录时,这是相同的行为。通过使用键字段添加映射公式字段,组件属性在“旧字段”中有一个值,并且它正确地知道它需要执行更新。

    这是一个基于此处找到的原始单元测试的附加单元测试和工作解决方案(用于 NHibernate.Test 项目)的存储库 - https://nhibernate.jira.com/browse/NH-2876

    https://github.com/kfehribach/NH2876

    肯特

    【讨论】:

      【解决方案2】:

      关于动态列映射的几行可以在这里找到:NHibernate Dynamic Columns Number。实际上,在这种情况下,这可能就是这种方式。

      <join table="ElemntValues" >
      
        <key column="ElementId" />
        <dynamic-component>
          ...
      

      但老实说,我最终得到了一些不同的解决方案。

      这是我的 C# 实体(例如联系人),带有一些 MuchMore 字段

      IDictionary _muchMore;
      
      // se the property name ... used later for mapping
      public virtual IDictionary MuchMore
      {
          get { return _muchMore?? (_muchMore= new Hashtable()); }
          set { _muchMore= value; }
      }
      

      现在,NHibernate 的映射可能性不可阻挡

      4.4. Dynamic models

      持久实体在运行时不一定必须表示为 POCO 类。 NHibernate 还支持动态模型(在运行时使用字典字典)。使用这种方法,您无需编写持久类,只​​需映射文件。

      ...

      首先,在映射文件中,entity-name 必须声明为而不是(或除了)名称

      这很酷。因为现在我们可以创建 ContactMuchMore 实体的品牌虚拟映射,这将代表连接的表:

      <class entity-name="ContactMuchMore"  table="Contact_MuchMore_table"
             dynamic-insert="true" dynamic-update="true" batch-size="25" >
      
        <id name="ID" column="Contact_ID" type="int">
          <generator class="foreign">
            <param name="property">Parent</param>
          </generator>
        </id>
        <one-to-one name="Parent" class="Contact" constrained="true" />
      

      难以置信...我们 NHibenrate 确实有映射实体 - 虚拟实体。它依赖于 Contact.. 所以我们可以使用真实的联系人作为 ID 生成器和one-to-one 映射

      这里是Contact.cs 映射:

      <class name="Contact"  ... >
        ...
        // here we mapp the property name
        // to our virtual entity 
        <one-to-one name="MuchMore" 
                    entity-name="ContactMuchMore"  
                    cascade="all" />
      

      一对一有一些阴暗面(两个表总是加载),但可以通过投影来解决。使用 cascade all - 将值持久保存到任何这些表(contact 或 contact_hasmore)中没有问题。

      我的回答是描述 xml 映射(不流利)。但我想如果概念清晰,我们可以流畅地使用类似的东西,或者异常使用 xml。

      【讨论】:

        猜你喜欢
        • 2021-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多