Edited:
I found another solution to call stored procedure via NHibernate and map it on my entity:
var campaignsItems = nhSession.CreateSQLQuery("exec Select_List_Campaigns :currentLatDegrees, :currentLonDegrees, :radiusInMiles, :pageSize, :currentPage, :search, :isTop, :topDealPercente")
.SetParameter("currentLatDegrees", currentLatDegrees)
.SetParameter("currentLonDegrees", currentLonDegrees)
.SetParameter("radiusInMiles", radius)
.SetParameter("pageSize", pageSize)
.SetParameter("currentPage", page)
.SetParameter("search", search)
.SetParameter("isTop", isTop)
.SetParameter("topDealPercente", topDealPercente)
.SetResultTransformer(Transformers.AliasToBean<CampaignListModel>())
.List<CampaignListModel>();
As you can see, here we can Set parameters and map results to our Entity with SetResultTransformer help. If properties in your class equals to the name of the columns in your stored procedure result set then all be fine.
Old question:
I have some stored procedure and whant to map my entity to result record set of this stored procedure. My hbm file:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<sql-query name="Select_Latest_Campaigns">
<return alias="cfl" class="Austradelia.Core.ProcedureResultEntities.CampaignForList, Austradelia.Core">
<return-property name="Id" column="Id"></return-property>
<return-property name="ShortDescription" column="ShortDescription"></return-property>
<return-property name="CampaignType" column="CampaignType"></return-property>
<return-property name="StartDate" column="StartDate"></return-property>
<return-property name="FinishDate" column="FinishDate"></return-property>
<return-property name="Quantity" column="Quantity"></return-property>
<return-property name="TotalRedeemsCount" column="TotalRedeemsCount"></return-property>
<return-property name="MerchantId" column="MerchantId"></return-property>
<return-property name="MerchantBusinessName" column="MerchantBusinessName"></return-property>
<return-property name="MerchantAddress" column="MerchantAddress"></return-property>
<return-property name="MerchantFollowersCount" column="MerchantFollowersCount"></return-property>
<return-property name="TipsCount" column="TipsCount"></return-property>
<return-property name="LikesCount" column="LikesCount"></return-property>
<return-property name="CategoryId" column="CategoryId"></return-property>
<return-property name="CategoryName" column="CategoryName"></return-property>
<return-property name="RowNumber" column="RowNumber"></return-property>
<return-property name="TotalCount" column="TotalCount"></return-property>
</return>
exec Select_Latest_Campaigns :currentLatDegrees, :currentLonDegrees, :radiusInMiles, :pageSize, :currentPage, :search
</sql-query>
</hibernate-mapping>
When I try to execute this query, I have this exception:
Exception Details: NHibernate.HibernateException: Errors in named queries: {Select_Latest_Campaigns}
On:
Line 43: return configuration.BuildSessionFactory();
Any ideas what wrong?
change persistence.xml by adding this property:
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory" />
i hope this help if not let me know what is you sql version !?
Related
Forgive me I am a newbie in NHibernate, I found some example in hbm.xml like below.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="test" >
<class name="test.FieldSetMapping" table="fieldsetmapping" discriminator-value="2352" lazy="false">
<id name="Id" column="fieldsetmapping_id" type="Int64">
<generator class="test.NHibernate.IdGenerator, test">
<param name="table">nextinstanceid</param>
<param name="column">next</param>
<param name="max_lo">9</param>
</generator>
</id>
<discriminator column="mapping_type" type="Int32" />
<version name="LastUpdateNumber" column="last_update_number" type="Int32" unsaved-value="-1"/>
<property name="OwnerName" column= "owner_name" type="String"/>
<component name="FieldSetDefinitionId" class="test.ObjectId">
<property name="InstanceId" column= "fieldsetdefinition_id" type="Int64"/>
</component>
<property name="OwnerTypeClassId" column= "owner_type" />
<bag name="FieldMappings" cascade="all-delete-orphan" generic="true" lazy="false">
<key column="fieldsetmapping_id" not-null="true" />
<one-to-many class="test.FieldSet.FieldMapping, test" />
</bag>
<property name="MappingHandlerClass" column="handler_class" />
</class>
<subclass name="test.EntityFieldSetMapping, test" discriminator-value="2353" extends="test.FieldSetMapping, test" lazy="false" >
<property name="TargetEntityType" type="test.Internal.NHibernate.ClassIdType, test" not-null="false">
<column name="target_entity_type"/>
</property>
</subclass>
<class ...>
...
</class>
<class ...>
...
</class>
</hibernate-mapping>
But I don't know what does discriminator mean . I check the Nhibernate Doc 5.1.6.
The <discriminator> element is required for polymorphic persistence
using the table-per-class-hierarchy mapping strategy and declares a discriminator
column of the table. The discriminator column contains marker values that tell
the persistence layer what subclass to instantiate for a particular row.A restricted
set of types may be used: String, Char, Int32, Byte, Short, Boolean, YesNo, TrueFalse.
Does it mean if the mapping_type > 2352 the NH will initialize the subclass test.EntityFieldSetMapping for the row of the table fieldsetmapping? thanks.
NHibernate will use the discriminator to detect which class needs to instantiate on a polymorphic scenario.
If mapping_type = 2352, it will create an instance of test.FieldSetMapping
if mapping_type = 2353, it will create an instance of test.EntityFieldSetMapping
Any other value should generate an exception.
I've seen a number of examples of this, and as far as I can tell my HBM file follows the same pattern, but it's not working. First, the file:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
<class name="ThinAir" mutable="false" lazy="true" >
<id name="JobId">
<generator class="native" />
</id>
<property name="UserLogin"/>
<property name="UserEmail"/>
<property name="DateProcessed"/>
<loader query-ref="myquery"/>
</class>
<sql-query name="myquery">
<return class="ThinAir">
<return-property name="JobID" column="JobId"/>
<return-property name="userLogin" column="UserLogin"/>
<return-property name="DateProcessed" column="DateProcessed"/>
<return-property name="userEmail" column="UserEmail"/>
</return>
<![CDATA[
SELECT DISTINCT JobID,
userLogin,
DateProcessed,
useremail
FROM dbo.someothertable
]]>
</sql-query>
</hibernate-mapping>
"myquery" in-and-of-itself, works. That is to say, if I call
var x = session.GetNamedQuery("myquery").List();
I get a correct List of ThinAir objects.
But, when I try to get a list of ThinAirs like this:
var submissions = session.CreateCriteria<ThinAir>().List<ThinAir>();
I get
Test method testThinAir threw exception:
NHibernate.Exceptions.GenericADOException: could not execute query
[ SELECT this_.JobId as JobId16_0_, this_.UserLogin as UserLogin16_0_, this_.UserEmail as UserEmail16_0_, this_.DateProcessed as DateProc4_16_0_ FROM ThinAir this_ ]
My interpretation of this phenomenon is that NH is ignoring my <loader> tag and so trying to load the data from the underlying table, which by default it assumes to be named ThinAir because that's the name of the entity class, only there isn't any ThinAir table, hence the error message.
Is that interpretation correct? And in any case, what am I doing wrong and how can I do it right?
Thanks in advance.
Michael
One way how to achieve this, would be to move the mapping from a query into the subselect:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
<class name="ThinAir" mutable="false" lazy="true" >
<subselect>
<![CDATA[
SELECT DISTINCT JobID,
userLogin,
DateProcessed,
useremail
FROM dbo.someothertable
]]>
</subselect>
... // rest of the mapping
I am trying to retrieve the count of items allocated to a container in my hbm file. I've done a bit of digging and managed to get my hbm code this far (below!). I want the count to be retrieved every time a container object is queried. I could use an interceptor but I assume there's a better way. Am I on the right track or should I use a different strategy to get the count loaded up?
Thanks.
P.S. We're using NH v2.2
<?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" assembly="MyEntities" namespace="Entities.Containers"> <class name="Container" table="[Container]" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="Id" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<property name="Capacity" column="Capacity">
<column name="Capacity" />
</property>
<property name="Description" column="Description" length="50" type="String">
<column name="Description" />
</property>
<loader query-ref="sqCurrentContainerAllocation"/> </class>
<sql-query name="sqCurrentContainerAllocation">
<return-scalar column="AllocatedItemsCount" type="int"></return-scalar>
SELECT COUNT(*) FROM [ContainerTracking]
WHERE [ContainerId] = :Id </sql-query>
</hibernate-mapping>
If you need to get some calculated property, you can use mapping with formula.
Let's extend your C# class:
public class Container
{
... // ID, Capacity, Description
public virtual int MyCount { get; set; }
And extend your mapping
<class name="Container" table="[Container]"
...
<property name="MyCount" insert="false" update="false" >
<formula>
(
SELECT count(*)
FROM [ContainerTracking] as ct
WHERE ct.[ContainerId] = Id
)
</formula>
</property>
the Id will be replaced with somethink like '_this.Id', the name of the column Id and its alias
This will of course load the count all the time (except projections) so think twice before use it
I am working on a legacy database which is quite intricate.
The table customers is shared with the suppliers and who created this structure used a flag to identify the customers.
Since I am only interested in working with records defined as customers I've added a where clause to my mapping:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="MyAssembly.Domain">
<class name="Customer" table="ANSADID" mutable="false" where="ANFCLI = 'Y'">
<composite-id>
<key-property name="CustomerCode" column="ANCOCO" type="String" length="10"></key-property>
<key-property name="Company" column="ANCOSO" type ="String" length="5"></key-property>
</composite-id>
<property name="Name" column="ANINCO" type="String" length="100"></property>
</class>
</hibernate-mapping>
As you can see I've pre-filtered all my customers with this clause: ANFCLI = 'Y'
Everything works perfectly fine if I query customers (the where clause is used):
var customers = session.QueryOver<Domain.Customer>()
.Where(t => t.Company == "ABC01")
.List();
But if I query the orders table - where I've got a many-to-one association:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="MyAssembly" namespace="MyAssembly.Domain">
<class name="Order" table="OCSAORH" mutable="false" where="OCHAMND = 0">
<composite-id>
<key-property name="Number" column="OCHORDN" type="String" length="10"></key-property>
<key-property name="Ver" column="OCHAMND" type="Int32"></key-property>
<key-property name="Company" column="OCHCOSC" type="String" length="5"></key-property>
</composite-id>
<many-to-one name="Customer" class="Customer" lazy="proxy" fetch="join">
<column name="OCHCLII" not-null="true"/>
<column name="OCHCOSC" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
the filter on the entity customers is lost.
I was reading somewhere that the where clause doesn't work on a association and you have to use a where clause on the collection (bag, set, etc etc) but, how can I do that with a many-to-one?
Thanks for you help.
What about mapping Customer using a discriminator using ANFCLI and then setting the discriminator value to 'Y'. I think NHibernate will treat this a little more rigourously than a where clause.
<class name="Customer" table="ANSADID" mutable="false" discriminator-value="Y">
<composite-id>
<key-property name="CustomerCode" column="ANCOCO" type="String" length="10" />
<key-property name="Company" column="ANCOSO" type ="String" length="5" />
</composite-id>
<discriminator column="ANFCLI" />
<property name="Name" column="ANINCO" type="String" length="100" />
</class>
I think degorolls is right:
You would need to have a super class called "Person", and two sub types called "Customer" and "Supplier".
Then you set your mapping so it uses the ANFCLI field as a discriminator, with the Y value for Customer and the N value for Supplier.
This way, you'll have a nice and transparent polymorphism.
(you'll be able to do stuff like "from Customer", or "from Supplier", and that will automagicaly add the where clause).
Hope that helps!
I'm also a newbie using NHibernate but perhaps you can map that relation (Order to Customer) using a bag (as if it would be one to many)!
I have a named Query that uses a view. I am unable to create a class mapping because this view does not have a Id column. I created a named query and set it to return it as a class, defining all the return values. However, I still receive a KeyNotFound Exception. If I set all of the columns to It returns the List. How can you tell NHibernate to map this to a class.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<sql-query name="GetAvailablePermissions" read-only="true">
<return alias="perm" class="Domain.AcsAvailablePermission, Domain">
<return-property name="Id" column="PermissionId"/>
<return-property name="Code" column="Code"/>
<return-property name="Category" column="Category"/>
<return-property name="Description" column="Description"/>
</return>
<![CDATA[
SELECT
[PermissionId]
, [Code]
, [Category]
, [Description]
FROM [dbo].[vw_Permission]
WHERE
[SiteId] = :SiteId
]]>
</sql-query>
</hibernate-mapping>
I did not find a NHibernate way so I changed everything to return-scalar. Then took the IList and converted it to a IList using LINQ.