Как я могу обработать возможно пустой список параметров при использовании именованного запроса в NHibernate?
-
02-10-2019 - |
Вопрос
У меня возникли проблемы при обработке ситуации, когда список параметров, отправленных в именованный запрос в 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>();
}
Однако, когда я передаю методу пустой список, я получаю эту ошибку:
Исключение System.NullReferenceException :Ссылка на объект не задана для экземпляра объекта.
Трассировка стека сервера:
в NHibernate.Движок.Типизированное значение..ctor(тип IType, значение объекта, EntityMode entityMode entityMode) в C:\junctions\BS\3rdParty Hibernate.2.1.2.GA-src\src Hibernate\Engine ypedValue.cs:строка 25
в NHibernate.Impl.AbstractQueryImpl.SetParameterList(имя строки, значения ICollection, тип IType) в C:\junctions\BS\3rdParty Hibernate.2.1.2.GA-src\src Hibernate\Impl\AbstractQueryImpl.cs:строка 647
в NHibernate.Impl.AbstractQueryImpl.SetParameterList(имя строки, значения ICollection) в C:\junctions\BS\3rdParty Hibernate.2.1.2.GA-src\src Hibernate\Impl\AbstractQueryImpl.cs:строка 666
в MyProject.Dao.MyClassDao.FilterByCategoryID(список`1 categoryIDs) в MyClassDao.cs:строка 50
Каков был бы наилучший способ решить эту проблему?Пожалуйста, обратите внимание, что именованный запрос, конечно, намного сложнее, чем представленный выше, поэтому я бы не хотел копировать его во вторую версию, которая не использует список параметров.
Решение
Я только что столкнулся с такой же проблемой, поэтому решил, что мне нужно поделиться решением:
Измените свой запрос следующим образом:
<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).
- Мы добавляем случайный идентификатор, который никогда не используется.Просто для того, чтобы убедиться, что В Оператор SQL является допустимым.
Таким образом, вы можете сохранить свой сложный запрос и просто добавить к нему дополнительные параметры.
Очевидным недостатком является то, что он передает ненужный параметр.
Но это делает свое дело.
Другие советы
Я полагаю, вы можете избежать этой ошибки, используя .NET's Cast
return session.GetNamedQuery("MyClass_FilterByCategoryID")
.SetParameterList("categoryIDs", categoryIDs)
.List().Cast<MyClassBE>();
Это должно возвращать пустой список, а не исключение.
проверьте, пуст ли список, и сделайте что-нибудь еще.в этом конкретном запросе вам нужны все 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>();
}