nHibernate命名查询将数据撤回到类映射

时间:2014-03-25 23:06:53

标签: nhibernate nhibernate-mapping

我今天只是感觉n00b使用了nHibernate并且正在努力映射到这个遗留数据集。

我有两个没有唯一键的表,当连接和过滤时,它们返回一个用户属性集合 - 结果集几乎看起来像一个键/值对。

相关表格:

  

用户:UserId,...

     

ProfileField:FieldId,Name,...

     

ProfileProperty:UserId,FieldId,Value ...

为用户获取正确数据的SQL查询将是:

select 
     profilefield.fieldid, 
     profilefield.Name, 
     ProfileProperty.Value 
from profilefield,
     profileproperty 
where profilefield.fieldid=profileproperty.fieldid 
      and profileproperty.userid={UserID}

我无法映射到课程,因为他们没有钥匙,我不认为我可以使用行李,因为我需要来自两个表的数据(profilefield中的名称,profileproperty中的值) )。

所以我决定尝试命名查询。我一直在使用来自nHibernate文档,Oren博客和本网站的例子,但没有运气。在所有情况下,要么没有返回数据,要么nHibernate抛出没有附加信息的nullvalue异常。

这是我目前的映射:

<class name="User" ...>
    ...
    <set name="Properties" lazy="true">
       <key/>
       <one-to-many class="UserProperty"/>
       <loader query-ref="GetUserProperties"/>
    </set>
</class>

<class name="UserProperty" mutable="false">
    <id name="Id" column="Id" />
    <property name="Name"/>
    <property name="Value" />
   <loader query-ref="GetUserProperties" />        
</class>

<sql-query name="GetUserProperties">
    <return alias="pp" class="UserProperty" lock-mode="upgrade"/>
    select
    profilefield.fieldid as {pp.Id},
    profilefield.name as {pp.Name},
    profileproperty.value as {pp.Value}
    from
    profileproperty,profilefield
    where profilefield.fieldid=profileproperty.fieldid
    and profileproperty.userid=?
</sql-query>

我已尝试使用<load-collection alias="pp" role="User.Properties"/>,但在命名查询异常中抛出了我无法解决的错误。我认为这与参数&#39;?&#39;有关。因为所有负载收集的例子都涉及命名参数而不是通用的&#39;?&#39;。

当使用上面的语句时,nHibernate确实运行了正确的查询:

  NHibernate: select
      profilefield.fieldid as Id31_0_,
      profilefield.name as Name31_0_,
      profileproperty.value as Value31_0_
      from
      profileproperty,profilefield
      where profilefield.fieldid=profileproperty.fieldid
      and profileproperty.userid=:p0;:p0 = 88162 [Type: Int32 (0)]

但是当我试图在我的单元测试中访问集合时,nHibernate会抛出:

  System.NullReferenceException : Object reference not set to an
  instance of an object.

更新:

如果我调用Session.GetNamedParameter(&#34; GetUserProperties&#34;)。SetParameter(&#34; id&#34;,88162).List()并更改&#39;?&#39;到&#39;:id&#39;我能够检索数据。所以我假设命名的sql-query语法是正确的,问题在于父对象的集合集。

1 个答案:

答案 0 :(得分:0)

我建议,至少在这种情况下,使用接近数据库结构的映射。这似乎并不那么糟糕。我们应该有UserProfileProperty集合。每个ProfileProperty都引用ProfileField

<class name="User" ...>
    ...
    <set name="ProfileProperties" lazy="true">
       <key column="UserId" />
       <one-to-many class="ProfileProperty"/>
    </set>
</class>

<class name="ProfileProperty" ...>
    ...
    <many-to-one class="ProfileField" column="FieldId" />
</class>

<class name="ProfileField" ... />

C#:

public class User
{
    public virtual IList<ProfileProperty> ProfileProperties { get; set; }
    ...

public class ProfileProperty
{
    public virtual ProfileField ProfileField { get; set; }
    ...

public class ProfileField 
{
    public virtual string Name { get; set; }
    ...

这是一种原生结构。这样我们就可以使用NHibernate查询的强大功能。写操作也会很顺利。

如果你真的需要这种人工收集,NHibernate也有解决方案。这将是 readonly ,但在某些情况下它可以帮助......

如果我们真的想在地图图层上解决问题,那么前往此处的方式是<subselect><composite-element>

<bag name="UserProperties">
 <subselect>
    select 
     profilefield.fieldid,  AS FieldId
     profilefield.Name,     AS Name
     ProfileProperty.Value, AS Value
     profileproperty.userid AS UserId
    from profilefield,
     profileproperty 
    where profilefield.fieldid=profileproperty.fieldid       
 </subselect>

  <key column="UserId" />
  <composite-element class="UserProperty" >
      <parent name="Parent" />
      <property name="FieldId" />
      <property name="Name" />
      <property name="Value" />
  </composite-element>
</bag>

和C#:

public class UserProperty
{
    public virtual User Parent { get; set; }
    public virtual string Name { get; set; }
    public virtual string Value { get; set; }
    public virtual int FieldId { get; set; }
}