Nhibernate Map复合元素

时间:2012-11-19 14:59:18

标签: c# linq nhibernate nhibernate-mapping

我有DB查看ALL_ATM_DEV_SATTRIB_VALS

DEVICE_ID   ATTRIB_ID    INT_VALUE    STRING_VALUE    DATE_VALUE

1           13           null         10.0.3.50       null
1           14           0            null            null
1           15           null         null            null

2           13           null         10.0.3.51       null
2           14           2            null            null
2           15           null         null            null

实体对象

public class AttributeValue: IAttributeValue
{
    public virtual string StringValue { get; set; }
    public virtual DateTime? DateValue { get; set; }
    public virtual int? IntValue { get; set; }
}

public class Device : IDevice
{
    public virtual long Id { get; set; }        

    public virtual IDictionary<long, IAttributeValue> Values { get; set; }
}

映射文件(hbm)

<class name="Device" table="DEVICES" lazy="true" >

<id name="Id" column="ID" ></id>

<map name="Values " batch-size="10" table="ALL_ATM_DEV_SATTRIB_VALS" lazy="true">
  <key column="DEVICE_ID" />
  <index column="ATTRIB_ID" type="System.Int64" />

  <composite-element class="AttributeValue">
    <property name="StringValue"  column="STRING_VALUE" />
    <property name="DateValue"  column="DATE_VALUE" />
    <property name="IntValue"  column="INT_VALUE" />
  </composite-element>
</map>

</class>

选择字典值可以正常工作,但是当我尝试在Linq表达式中使用它时

List<IDevice> a = dc.Get<IDevice>()
                    .Where(x=>x.Values[13].StringValue
                                          .ToLower().Contains("10.0.3"))
                    .ToList();

nhibernate throw exception

System.InvalidOperationException: Cannot create element join for a collection of non-entities!

在对象Device中,我需要IDictionary。键是ATTRIB_ID(长),值是AttributeValue

1 个答案:

答案 0 :(得分:0)

Nhibernate无法使用IDictionary<long, IAttributeValue>创建sql-query,因为IAttributeValue不会在hbm中映射为实体。

但我解决了这个问题。

我将一个IDictionary的映射替换为三个更简单:

 <map name="StringValues" table="ALL_ATM_DEV_SATTRIB_VALS" lazy="true" fetch="select">
  <key column="DEVICE_ID" />
  <index column="ATTRIB_ID" type="System.Int64" />
  <element column="STRING_VALUE" type="System.String"/>
</map>
<map name="DateValues" table="ALL_ATM_DEV_SATTRIB_VALS" lazy="true" fetch="select">
  <key column="DEVICE_ID" />
  <index column="ATTRIB_ID" type="System.Int64" />
  <element column="DATE_VALUE" type="System.DateTime"/>
</map>
<map name="IntValues" table="ALL_ATM_DEV_SATTRIB_VALS" lazy="true" fetch="select">
  <key column="DEVICE_ID" />
  <index column="ATTRIB_ID" type="System.Int64" />
  <element column="INT_VALUE" type="System.Int64"/>
</map>

我将此地图仅用于创建结果sql-query ,这就是为什么lazy=true存在的原因,以及 永远不会在实体IDevice

中访问它们

此映射的数据一次选择了另一个sql-query,因为延迟初始化会导致数据库上出现n + 1个sql查询。

我的问题中的Linq查询转换为:

List<IDevice> a = dc.Get<IDevice>()
                .Where(x=>x.StringValues[13].ToLower().Contains("10.0.3"))
                .ToList();

IDevice实体中定义了三张地图:

    public virtual IDictionary<long, long> IntValues { get; set; }
    public virtual IDictionary<long, string> StringValues { get; set; }
    public virtual IDictionary<long, DateTime> DateValues { get; set; }