我正在尝试使用nHibernate将存储过程的输出映射到项目中的对象。
该对象是这样的:
public class NewContentSearchResult
{
public string Name { get; set; }
public string ContentType { get; set; }
public int Count { get; set; }
public int CMIId { get; set; }
public int FeatureId { get; set; }
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
,映射如下所示:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Class.Assembly"
namespace="Class.Assembly"
default-lazy="false" default-cascade="none">
<class name="NewContentSearchResult" mutable="false" check="none">
<composite-id unsaved-value="none">
<key-property name="CMIId" type="int" />
<key-property name="FeatureId" type="int" />
</composite-id>
<property name="ContentType" type="string" />
<property name="Name" type="string" />
<property name="Count" type="int" />
</class>
<sql-query name="spWebGetNewContentBySalesRole">
<return class="NewContentSearchResult" lock-mode="read">
<return-property name="Name" column="Name" />
<return-property name="ContentType" column="FeatureDesc" />
<return-property name="Count" column="Number" />
<return-property name="CMIId" column="CMIId" />
<return-property name="FeatureId" column="FeatureId" />
</return>
exec core.spWebGetNewContentBySalesRole :SalesRoleId
</sql-query>
</hibernate-mapping>
存储的proc调用是正确的,我得到了SalesRoleId 266的结果(作为示例):
CMIId FeatureDesc FeatureId Name Count
4000719 Guest Book 12 Charlie Brown 2
4000719 Audio Guest Book 3 Charlie Brown 1
没有复合键(仅使用CMIId)它可以正常工作,除非有2个结果(如上所述)共享CMIId ...第二个被第一个覆盖。
我必须使用复合键,CMIId / FeatureId是逻辑组合。
当我现在运行时,我得到一个例外:
NHibernate.ADOException: could not execute query
[ exec core.spWebGetNewContentBySalesRole ? ]
Name: SalesRoleId - Value: 266
[SQL: exec core.spWebGetNewContentBySalesRole ?] ---> System.IndexOutOfRangeException: CMIId22_0_.
答案 0 :(得分:5)
好的,进一步的研究使我确信当你使用存储过程时,在nHibernate中不可能有复合id。
为此,我修改了我的SQL以包含rownumber(),我将其用作id。我只能这样做,因为它是只读的,没有写入数据库,但它适用于我的目的。
答案 1 :(得分:2)
过去当我使用复合键时,我总是必须为该ID创建一个单独的类,其类的属性与复合键的单独键匹配。你试过这个吗?
答案 2 :(得分:2)
正如在接受的答案中所提到的,我最终使用ROWNUM函数在Oracle中使用了唯一的行号hack。后来,我在使用不同参数重用查询时遇到了问题。似乎nHibernate记住了id并希望将它们与新返回的结果相关联,从而带回不正确的行。我通过将行号与这样的时间戳组合来修复此问题:
(ROWNUM * 10000000000 + dbms_utility.get_time) AS ROW_ID
通过这种方式,您可以确保每次都为查询结果获取全新的ID。只需确保使用足够大的整数来保存映射对象中的值。我在c#.net中使用了ulong
,这是8个字节。您也可以从乘数中取出几个0来缩短ID。
答案 3 :(得分:1)
当天晚些时候,但我可以选择Mark Struzinski - 这是可能的。
我最近遇到了这个问题并通过为复合键使用单独的类并使用映射中的元素来解决它。
<sql-query name="spWebGetNewContentBySalesRole" >
<return class="NewContentSearchResult">
<return-property name="NewContentSearchResultKey">
<return-column name="CMIIdColumn" />
<return-column name="FeatureIdColumn" />
</return-property>
<return-property name="Name" column="Name" />
<return-property name="ContentType" column="FeatureDesc" />
<return-property name="Count" column="Number" />
</return>
exec core.spWebGetNewContentBySalesRole :SalesRoleId
</sql-query>
请注意,return-column元素中的“name”属性表示结果集中的名称,并且应与id类中的属性的顺序相同。