Hibernate 中没有复合键的一对多关联
One to many association in Hibernate without composite key
Table:
tradeId | actionTradeId | type | date
其中 tradeId+actionTradeId
- 复合键
休眠映射:
<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>
我需要的
我想在与此查询相同的 table 上进行映射:
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
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);
备注
- 由于 属性-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>
Table:
tradeId | actionTradeId | type | date
其中 tradeId+actionTradeId
- 复合键
休眠映射:
<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>
我需要的
我想在与此查询相同的 table 上进行映射:
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
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);
备注
- 由于 属性-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>