Hibernate中的一对多关联,没有复合键

时间:2015-01-25 17:40:32

标签: java hibernate nhibernate hibernate-mapping

表格

tradeId | actionTradeId | type | date

其中tradeId+actionTradeId - 复合键

Hibernate映射:

<class name="Trade" table="TRADE">
 <composite-id name="id" class="TradePK">
        <key-property name="tradeId" type="long" column="trade_id"/>
        <key-property name="actionTradeId" type="long"        column="action_trade_id"/>
  </composite-id>
<property name="type" length="1"/>
<property name="date"/>
</class>

我需要什么

我希望像在此查询中一样在同一个表上进行映射:

select * 
from Trade 
where action_trade_id = trade_id and type = 'S'

首先我尝试了这种方式,但它失败了,因为我有复合键:

<set name="sellTrades" inverse="false" lazy="true" where="type='S'">
            <key>
                <column name="action_trade_id" not-null="true" />
            </key>
            <one-to-many class="Trade" />
</set>

示例数据:

 tradeId| actionTradeId | type| date 
 --------------------------------------
    11         22          S    date (so for this entity I need list with <55, 66>)
    33         44          S    date 
    55         11          S    date
    66         11          S    date

1 个答案:

答案 0 :(得分:1)

public class ClassWithCompositeKey
{
    private int id1;
    private int id2;

    public ClassWithCompositeKey()
    {
        Children = new List<ClassWithCompositeKey>();
    }

    public virtual int Id1
    {
        get { return id1; }
        set { id1 = value; }
    }
    public virtual int Id2
    {
        get { return id2; }
        set { id2 = value; }
    }

    public virtual string Type { get; set; }

    public virtual ICollection<ClassWithCompositeKey> Children { get; protected set; }

    public override bool Equals(object obj)
    {
        var other = obj as ClassWithCompositeKey;
        return other != null && Id1 == other.Id1 && Id2 == other.Id2;
    }

    public override int GetHashCode()
    {
        return (Id1 << 16) | Id2;  // optimized for Id's < 16 bit
    }
}

映射

public class ClassWithCompositeKeyMap : ClassMap<ClassWithCompositeKey>
{
    public ClassWithCompositeKeyMap()
    {
        CompositeId()
            .KeyProperty(x => x.Id1)
            .KeyProperty(x => x.Id2);

        Map(x => x.Type);

        Map(x => id1).Column("Id1").Access.Using("field").ReadOnly();

        HasMany(x => x.Children)
            .Where("Type = 'S'")
            .PropertyRef("id1")
            .KeyColumns.Add("Id2")
            .Inverse();
    }

    public virtual int id1 { get; set; }
}

和查询

using (var tx = session.BeginTransaction())
{
    session.Save(new ClassWithCompositeKey { Id1 = 11, Id2 = 22, Type = "F" });
    session.Save(new ClassWithCompositeKey { Id1 = 55, Id2 = 11, Type = "S" });
    session.Save(new ClassWithCompositeKey { Id1 = 66, Id2 = 11, Type = "S" });
    tx.Commit();
}
session.Clear();

var x = session.Get<ClassWithCompositeKey>(new ClassWithCompositeKey { Id1 = 11, Id2 = 22 });
Assert.Equal(2, x.Children.Count);

注意

  • 因为property-ref
  • 而禁用了对集合的延迟加载
  • 小心将Children集合与代码中应属于它的实例同步,这样您就不会有破碎的模型

更新为hbm

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="ClassWithCompositeKey">
    <composite-id>
      <key-property name="Id1" column="Id1"/>
      <key-property name="Id2" column="Id2"/>
    </composite-id>
    <bag inverse="true" lazy="true" name="Children" where="Type = 'S'">
      <key property-ref="id1">
        <column name="Id2" />
      </key>
      <one-to-many class="ClassWithCompositeKey" />
    </bag>
    <property name="Type" column="Type" />
    <property access="field" name="id1" column="id1" insert="false" update="false"/>
  </class>
</hibernate-mapping>