Comment puis-je gérer un paramètre qui peut être vide liste lorsque vous utilisez une requête nommée dans NHibernate?
-
02-10-2019 - |
Question
Je vais avoir des questions sur la manipulation d'une situation dans laquelle une liste des paramètres envoyés à une requête nommée dans NHibernate est vide.
Ceci est un exemple de ma situation:
<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>
Ceci est la méthode qui est appelée:
public IList<MyClassBE> FilterByCategoryID(List<String> categoryIDs)
{
return session.GetNamedQuery("MyClass_FilterByCategoryID")
.SetParameterList("categoryIDs", categoryIDs)
.List<MyClassBE>();
}
Cependant, quand je passe une liste vide à la méthode, je reçois cette erreur:
System.NullReferenceException:. Référence d'objet non définie à une instance d'un objet
trace de pile du serveur:
à NHibernate.Engine.TypedValue..ctor (type itype, la valeur de l'objet, EntityMode EntityMode) dans C: \ jonctions de BS \ 3rdParty \ NHibernate.2.1.2.GA-src \ src \ Hibernate \ Engine \ TypedValue. cs: ligne 25
à NHibernate.Impl.AbstractQueryImpl.SetParameterList (nom String, vals ICollection, le type itype) dans C: \ jonctions \ BS \ 3rdparty \ NHibernate.2.1.2.GA-src \ src \ Hibernate \ Impl \ AbstractQueryImpl.cs : ligne 647
à NHibernate.Impl.AbstractQueryImpl.SetParameterList (nom String, vals ICollection) dans C: \ jonctions de BS \ 3rdParty \ NHibernate.2.1.2.GA-src \ src \ Hibernate \ Impl \ AbstractQueryImpl.cs: ligne 666
à MyProject.Dao.MyClassDao.FilterByCategoryID (List`1 categoryIDs) dans MyClassDao.cs: ligne 50
Quelle serait la meilleure façon de résoudre ce problème? S'il vous plaît noter que la requête du nom est bien sûr beaucoup plus compliqué que celui présenté ci-dessus, donc je voudrais éviter la copier dans une seconde version qui n'utilise pas la liste des paramètres.
La solution
Je viens face à la même question, donc je si je dois partager la solution:
Modifier votre requête à:
<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>
Et le code:
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>();
}
Explication:
- Nous modifier une requête d'ignorer les catégories lorsqu'aucune telles disponibles.
- Nous modifier un paramètre supplémentaire pour indiquer ( 1 ).
- Nous ajoutons ID aléatoire qui est jamais utilisée. Juste pour vous assurer que la instruction SQL est valide.
Ainsi, cette façon vous pouvez garder votre requête complexe et il suffit d'ajouter des paramètres supplémentaires à elle.
inconvénient évident est que ce paramètre passe inutile.
Mais il fait le travail.
Autres conseils
Je crois que vous pouvez éviter cette erreur en utilisant la Cast
de .NET
return session.GetNamedQuery("MyClass_FilterByCategoryID")
.SetParameterList("categoryIDs", categoryIDs)
.List().Cast<MyClassBE>();
Cela devrait retourner une liste vide, pas une exception.
test si la liste est vide et faire autre chose. dans cette requête particulière que vous voulez tous les MyClassBE qui ne sont pas dans la catégorie ids qui signifie tous:
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>();
}