【问题标题】:NHibernate GetNamedQuery executes stored procedure but returns empty listNHibernate GetNamedQuery 执行存储过程但返回空列表
【发布时间】:2014-01-11 00:07:36
【问题描述】:

我有一个存储过程,它在使用此脚本在 SQL Studio Management Express 中进行测试时返回 2 条记录:

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

当我尝试使用以下映射文件从 NHibernate 执行相同的存储过程时,我得到 0 个结果。

<?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>

执行上述存储过程的方法是:

   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;
    }

我什至为这个激活类型创建了一个新的映射文件,即使没有关联的表但是 NHibernate 没有返回正确的结果。在过程的映射文件中取消注释类型映射定义不会改变结果。我在这里遗漏了什么吗?

我没有发现异常,所以看起来程序正在执行。

更新:1 删除了对 AddStoredProcedureParameters 的调用并替换为方法体。

UPDATE 2添加存储过程:

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

【问题讨论】:

    标签: nhibernate stored-procedures sql-server-2012


    【解决方案1】:

    我刚刚尝试了您的映射(尽可能相同),您的 1) 映射和 2) 调用正常。除了我不确定 AddStoredProcedureParameters

    内部的调用这一事实之外

    所以,这是有效的:

    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[]>(); 
    

    这是有效的。也就是说。您的映射工作正常。 SQL 调用 (exec sp) 被触发,因为如果找不到命名查询,或者发生其他一些问题,我们将得到一个 Exception

    目前唯一怀疑的是黑匣子AddStoredProcedureParameters(它不能切换开始和结束日期吗?)

    我建议,在 SQL Server Profiler 中检查您的单元测试,您将看到传递给 DB 的内容...然后您可以重新执行。

    【讨论】:

    • +1 用于参考 SQL Profiler。因为,我在 Express 上,我使用了来自 expressprofiler.codeplex.com 的 ExpressProfiler,它确认正在执行以下内容: exec sp_executesql N'exec [sp_get_deactivation_list] @companyId=@p0, @startDate=@p1, @endDate=@p2', N'@p0 int,@p1 日期时间,@p2 日期时间',@p0=1,@p1='2013-10-26 00:00:00',@p2='2020-12-16 00:00:00 ' 去。还是没有输出。你为什么要做 query.List 而不是 query.List
    • 我有一个类似的存储过程,称为 GetTransmissionSum,通过 NHibernate 成功执行。执行此命令时,Express Profiler 提供 31 个 CPU、3788 个读取和 41 毫秒的持续时间。但是,GetDeactivationList 执行时,CPU 为 0,Reads 为 3,Duration 为 0ms。当我在 Studio Management Express 中针对 GetDeactivationList 执行测试脚本时,CPU 为 125,读取时间为 3991,持续时间为 124ms。
    • 当我重新执行传递给数据库的查询时,它返回的计数为 0。嗯。
    • 在这里感觉自己像个傻瓜。查询正在执行,但没有满足输入参数的结果。在 SME 中测试时,使用的结束时间是 2020 年 12 月 26 日,但在我的单元测试中,使用的是 2020 年 12 月 16 日。
    • 回答第一个问题:为什么object[] - 因为我知道我正在为每个 row 使用 columns 的对象数组.你的测量结果真的很奇怪;(因为现在我们知道,正确的 SQL 语句被触发了......使用正确的参数......但是为什么它没有给出任何结果?
    【解决方案2】:

    如果执行您拥有的存储过程是您的主要目的(不完全使用 GetNamedQuery),您可以使用以下内容:

    假设你的方法的参数是:int? id,日期时间?从日期,日期时间? toDate(所有可为空的值)

    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;
    

    在您的 TOut 类的映射文件中,只需要正常的相关属性即可。

    【讨论】:

    • 谢谢,但还有其他与调用 GetNamedQuery 及其参数无关的问题。
    【解决方案3】:

    如果 Activation 是具有 nhibernate 的非托管实体,您可以使用它:

    var query = session.GetNamedQuery(procedureName);
    
    AddStoredProcedureParameters(query, parameters);
    
    result = query.SetResultTransformer(Transformers.AliasToBean(typeof(TOut)))
        .List<TOut>();
    

    如果确实尝试添加alias:

    <return alias="activation" class="Activation">
         ...
    </return>
    

    例如:

    <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>
    

    参考here 是解决问题的更多方法。 只是你需要怎么说nhibernate怎么返回数据,“this”列“resolve this”属性。

    对不起,我的英语不好。

    【讨论】:

    • 感谢您的回复。 query.SetResultTransformer().List() 是我在遇到相关帖子之前的代码。会再试一次,但我记得,那没有用。你能澄清一下第二段吗?我应该取消注释激活映射并添加别名吗?
    猜你喜欢
    • 2015-11-02
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多