Reputation: 2871
I'm trying to map the output of a stored procedure to an object in my project using nHibernate.
The object is delcared like this:
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();
}
}
and the mapping looks like this:
<?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>
The stored proc call is correct, and I get back results that look like this for SalesRoleId 266 (as an example):
CMIId FeatureDesc FeatureId Name Count
4000719 Guest Book 12 Charlie Brown 2
4000719 Audio Guest Book 3 Charlie Brown 1
Without the composite key (using just the CMIId) it works just fine, except when there are 2 results (as above) that share a CMIId...the 2nd is overwritten by the first.
I have to use a composite key, and CMIId/FeatureId is the logical combination.
When I run this now, I get an exception:
NHibernate.ADOException: could not execute query
[ exec core.spWebGetNewContentBySalesRole ? ]
Name: SalesRoleId - Value: 266
[SQL: exec core.spWebGetNewContentBySalesRole ?] ---> System.IndexOutOfRangeException: CMIId22_0_.
Upvotes: 2
Views: 2651
Reputation: 416
A bit late in the day, but I can second Mark Struzinski - this is possible.
I ran into this problem recently and solved it by using a separate class for the composite key and using elements within the mapping as follows.
<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>
Note that the "name" attributes inside the return-column elements represent the names in the result set, and should be in the same order as the properties in the id class.
Upvotes: 1
Reputation: 9429
As mentioned in the accepted answer, I ended up using a unique row number hack in Oracle by using the ROWNUM function. Later, I ran into a problem when reusing the query with different parameters. Seems that nHibernate remembered the ids and wanted to associate them with newly returned results, thus bringing back incorrect rows. I fixed this by combining the row number with a timestamp like this:
(ROWNUM * 10000000000 + dbms_utility.get_time) AS ROW_ID
This way you're guaranteed to get completely new ids for your query results every time. Just make sure that you use a large enough integer to hold the value in your mapped object. I use a ulong
in c#.net which is 8 bytes. You can also take a few 0s out of the multiplier to make the ID shorter.
Upvotes: 2
Reputation: 2871
Ok, further research has convinced me that it's not possible to have composite ids in nHibernate when you use a stored procedure.
To that end, I modified my SQL to include rownumber() and I'm using that as an id. I can only do this because it's read-only, with no writing to the db, but it works for my purpose.
Upvotes: 5
Reputation: 33471
In the past when I've used a composite-key I've always had to create a separate class for that ID with the properties of the class matching the separate keys for the composite. Have you tried this?
Upvotes: 2