I have a stored procedure with two parameters that returns an int.
my mapping.hbm.xml
<sql-query name="CreateAttribute">
<query-param name="idAttrType" type="int"/>
<query-param name="idSystemUser" type="int"/>
call CreateAttribute :idAttrType,:idSystemUser
</sql-query>
C# usage
var t = session.GetNamedQuery("CreateAttribute");
t.SetInt32("idAttrType", 12);
t.SetInt32("idSystemUser",int.Parse(id));
var result = t.List();
Then i receive the folowing:
[SQL: call CreateAttribute ?p0,?p1] ---> MySql.Data.MySqlClient.MySqlException: You have an error in your SQL syntax;
Any suggestions?
Should it not be:-
<sql-query name="CreateAttribute">
<query-param name="idAttrType" type="int"/>
<query-param name="idSystemUser" type="int"/>
call CreateAttribute(:idAttrType,:idSystemUser);
</sql-query>
Notice the braces around the params.
edit run this against your MySql database, does it run?
call CreateAttribute(0,0);
Modified the call as following
SELECT call CreateAttribute(0,0); -- it worked
new mapping now is
<sql-query name="CreateAttribute">
<query-param name="idAttrType" type="int"/>
<query-param name="idSystemUser" type="int"/>
select CreateAttribute(:idAttrType,:idSystemUser);
</sql-query>
Related
NHibernate throw exception with sql server not equal to operator <>.
<sql-query name="Select">
<return alias="OrderStock" class="OrderStock"/>
select * from OrderStock WHERE dh.DATE_UNLOADED <> '1753-01-01'
</sql-query>
Name cannot begin with the '>' character
We can escape symbols <> with <> like this:
<sql-query name="Select">
<return alias="OrderStock" class="OrderStock"/>
select * from OrderStock WHERE dh.DATE_UNLOADED <> '1753-01-01'
</sql-query>
Or we can use xml raw text escaping with <![CDATA[ .... ]]>:
<sql-query name="Select">
<return alias="OrderStock" class="OrderStock"/>
<![CDATA[
select * from OrderStock WHERE dh.DATE_UNLOADED <> '1753-01-01'
]]>
</sql-query>
I have a Stored Procedure that returns 2 records when tested in SQL Studio Management Express using this script:
declare #route_id_param as varchar(10), #start_time as datetime, #start_date as datetime, #end_date as datetime
set #start_time = GETDATE()
set #start_date = CONVERT(DATETIME,'10/26/2013',101)
set #end_date = CONVERT(DATETIME,'12/26/2020',101)
exec dbo.sp_get_deactivation_list #companyId=1, #startDate = #start_date, #endDate = #end_date;
select execution_time_in_ms = DATEDIFF(millisecond, #start_time, getdate())
GO
When I attempt to executed same stored procedure from NHibernate, using the following mapping file, I get 0 results.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="HGT.IridiumAirtime.Service"
namespace="HGT.IridiumAirtime.Service.Model">
<sql-query name="GetDeactivationList" callable="true">
<query-param name="companyId" type="int"/>
<query-param name="startDate" type="DateTime"/>
<query-param name="endDate" type="DateTime"/>
<!--<return class="Activation">
<return-property column="MobileId" name="MobileId" />
<return-property column="RadioAddress" name="RadioAddress" />
<return-property column="DeactivationDate" name="DeactivationDate" />
</return>-->
exec [sp_get_deactivation_list] #companyId=:companyId, #startDate=:startDate, #endDate=:endDate
</sql-query>
</hibernate-mapping>
The method that executed said Stored Procedure is:
public IEnumerable<TOut> ExecuteStoredProcedure<TOut>(string procedureName, IList<SqlParameter> parameters)
{
IEnumerable<TOut> result;
using (var session = _sessionFactory.OpenSession())
{
var query = session.GetNamedQuery(procedureName);
foreach (var parameter in parameters)
{
query.SetParameter(parameter.ParameterName, parameter.Value);
}
AddStoredProcedureParameters(query, parameters);
result = query.List<TOut>();
}
return result;
}
I even created a new mapping file for this Activation type even though there is no associated table but NHibernate does not return the correct result. Un-commenting the type mapping definition within the procedure's mapping file does not change outcome. Am I missing something here?
I get no exceptions, so it looks like procedure is being executed.
UPDATE: 1 Removed call to AddStoredProcedureParameters and replaced with method body.
UPDATE 2 Adding Stored Procedure:
if OBJECT_ID ( 'dbo.[sp_get_deactivation_list]', 'P' ) is not null
drop procedure dbo.[sp_get_deactivation_list];
go
create procedure [dbo].[sp_get_deactivation_list]
#companyId int,
#startDate DateTime,
#endDate DateTime
as
begin
select
assMobileRadio.Mobile_ID as MobileId,
tblRadioinfo.Radio_Address as RadioAddress,
tblRadioinfo.Deactivation_Date as DeactivationDate
from tblRadioinfo
left join assMobileRadio
on tblRadioinfo.Radio_ID = assMobileRadio.Radio_ID
where tblRadioinfo.Radio_Type_ID in (2, 4, 7)
and tblRadioinfo.Company_ID = #companyId
and tblRadioinfo.Deactivation_Date <= #endDate
and tblRadioinfo.Deactivation_Date >= #startDate
and tblRadioinfo.Radio_Address in (select IMEI from [airtime_cdrs] where Effective_Date > #startDate and Effective_Date < #endDate)
from airtimes_cte for xml path('')),1,1,''))
ORDER BY tblRadioinfo.Deactivation_Date
end
I've just tried your mapping (the same as possible) and your 1) mapping and 2) call is OK. Except the fact that I am not sure about the call inside of the AddStoredProcedureParameters
So, this is working:
var query = session.GetNamedQuery("GetDeactivationList");
query.SetParameter("companyId", 1);
query.SetParameter("startDate", new DateTime(2013,10,26));
query.SetParameter("endDate", new DateTime(2020,12,26));
// if the <return class="Activation"> is commented ... we'll get object[]
var list = query.List<object[]>();
And this is working. Other words. Your mapping is working. The SQL call (exec sp) is fired, because if the named query won't be find, or some other issues would happen, we will get an Exception.
The only suspected right now is the black box AddStoredProcedureParameters (could not it switch start and end date?)
I would suggest, do check your Unit test in the SQL Server Profiler, you will see what is passed to DB... and you can take and reexecute.
If executing the stored procedure you have is your main purpose (not exactly using GetNamedQuery), you can use the following:
Assuming that your methods' arguments are: int? id, DateTime? fromDate, DateTime? toDate (all nullable values)
IList<TOut> result = session.CreateSQLQuery("exec [dbo].[sp_get_deactivation_list]:param1, :param2, :param3")
.SetParameter("param1", id, NHibernateUtil.Int32)
.SetParameter("param2", fromDate, NHibernateUtil.DateTime)
.SetParameter("param3", toDate, NHibernateUtil.DateTime)
.SetResultTransformer(Transformers.AliasToBean<TOut>()).List<TOut>();
return result;
And in your mapping file for class TOut, just have the related properties as normal.
If Activation is non-managed entity with nhibernate you can use this:
var query = session.GetNamedQuery(procedureName);
AddStoredProcedureParameters(query, parameters);
result = query.SetResultTransformer(Transformers.AliasToBean(typeof(TOut)))
.List<TOut>();
If does try to add alias:
<return alias="activation" class="Activation">
...
</return>
For example:
<sql-query name="mySqlQuery">
<return alias="person" class="eg.Person">
<return-property name="Name" column="myName"/>
<return-property name="Age" column="myAge"/>
<return-property name="Sex" column="mySex"/>
</return>
SELECT person.NAME AS myName,
person.AGE AS myAge,
person.SEX AS mySex,
FROM PERSON person WHERE person.NAME LIKE :name
</sql-query>
Reference here are some more ways to solve your issue.
Just you need how to say to nhibernate how return the data, "this" column "resolve this" property.
Sorry for my poor english.
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
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 !?
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.