在NHibernate中使用命名查询时,如何处理可能为空的参数List?

时间:2010-09-13 12:34:22

标签: nhibernate parameter-passing named-query

我遇到的问题是处理发送到NHibernate中的命名查询的参数列表为空的情况。

这是我的情况的一个例子:

<sql-query name="MyClass_FilterByCategoryID">
    <return alias="MyClass" class="MyProject.BusinessEntities.MyClassBE"/>
    <![CDATA[
    SELECT DISTINCT MyClass.*
    FROM MyClassTable MyClass
    WHERE 1 = 1
            AND MyClassTable.CategoryID NOT IN (:categoryIDs) 
    ]]>
</sql-query>

这是被调用的方法:

public IList<MyClassBE> FilterByCategoryID(List<String> categoryIDs)
{
    return session.GetNamedQuery("MyClass_FilterByCategoryID")
        .SetParameterList("categoryIDs", categoryIDs)
        .List<MyClassBE>();
}

但是,当我将空List传递给方法时,我收到此错误:

  

System.NullReferenceException:未将对象引用设置为对象的实例。

     

服务器堆栈跟踪:

     

位于C:\ junctions \ BS \ 3rdParty \ NHibernate.2.1.2.GA-src \ src \ NHibernate \ Engine \ TypedValue中的NHibernate.Engine.TypedValue..ctor(IType类型,对象值,EntityMode entityMode)。 cs:第25行

     

在NHibernate.Impl.AbstractQueryImpl.SetParameterList(字符串名称,ICollection的瓦尔斯,ITYPE型)在C:\结\ BS \的3rdParty \ NHibernate.2.1.2.GA-SRC \ SRC \ NHibernate的\默认地将Impl \ AbstractQueryImpl.cs :第647行

     

在NHibernate.Impl.AbstractQueryImpl.SetParameterList(字符串名称,ICollection的瓦尔斯)在C:\结\ BS \的3rdParty \ NHibernate.2.1.2.GA-SRC \ SRC \ NHibernate的\默认地将Impl \ AbstractQueryImpl.cs:线666

     

在MyClassDao.cs中的MyProject.Dao.MyClassDao.FilterByCategoryID(List`1 categoryIDs):第50行

解决这个问题的最佳方法是什么?请注意,命名查询当然比上面提到的要复杂得多,所以我想避免将其复制到不使用参数列表的第二个版本。

3 个答案:

答案 0 :(得分:3)

我刚遇到同样的问题,所以我需要分享解决方案:

将您的查询修改为:

<sql-query name="MyClass_FilterByCategoryID">
    <return alias="MyClass" class="MyProject.BusinessEntities.MyClassBE"/>
    <![CDATA[
    SELECT DISTINCT MyClass.*
    FROM MyClassTable MyClass
    WHERE 
            (
              :hasCatogories=0
              or (:hasCatogories=1 and MyClassTable.CategoryID NOT IN (:categoryIDs) )
            )
    ]]>
</sql-query>

代码:

public IList<MyClassBE> FilterByCategoryID(List<String> categoryIDs)
{
    return session.GetNamedQuery("MyClass_FilterByCategoryID")
        .SetIn32("hasCatogories", categoryIDs.Any() ? 1 : 0)
        .SetParameterList("categoryIDs", categoryIDs.Any() ? categoryIDs : new [] {"fake-non-existing-id"})
        .List<MyClassBE>();
}

<强>解释

  1. 我们修改查询以在没有可用时忽略类别。
  2. 我们修改其他参数以指示( 1 )。
  3. 我们添加从未使用过的随机ID。只是为了确保 IN SQL语句有效。
  4. 这样,您可以保留复杂的查询,只需添加其他参数即可。

    明显的缺点是它传递了不必要的参数。

    但它确实起到了作用。

答案 1 :(得分:0)

我相信你可以通过使用.NET Cast

return session.GetNamedQuery("MyClass_FilterByCategoryID")
    .SetParameterList("categoryIDs", categoryIDs)
    .List().Cast<MyClassBE>();
来避免这个错误

那应该返回一个空列表,而不是例外。

答案 2 :(得分:0)

测试列表是否为空并执行其他操作。 在此特定查询中,您希望所有不在类别ID中的MyClassBE表示所有这些:

public IList<MyClassBE> FilterByCategoryID(List<String> categoryIDs)
{
    if (categoryIDs.Count > 0)
        return session.GetNamedQuery("MyClass_FilterByCategoryID")
            .SetParameterList("categoryIDs", categoryIDs)
            .List<MyClassBE>();
    else
        return session.CreateQuery("from MyClassBe").List<MyClassBE>();
}