我今天只是感觉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语法是正确的,问题在于父对象的集合集。
答案 0 :(得分:0)
我建议,至少在这种情况下,使用接近数据库结构的映射。这似乎并不那么糟糕。我们应该有User
个ProfileProperty
集合。每个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; }
}