Come posso gestire una lista di parametri che può essere vuoto quando si utilizza una query denominata in NHibernate?
-
02-10-2019 - |
Domanda
sto avendo problemi di gestione di una situazione in cui un elenco di parametri inviato a una query denominata in NHibernate è vuoto.
Questo è un esempio della mia situazione:
<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>
Questo è il metodo che viene chiamato:
public IList<MyClassBE> FilterByCategoryID(List<String> categoryIDs)
{
return session.GetNamedQuery("MyClass_FilterByCategoryID")
.SetParameterList("categoryIDs", categoryIDs)
.List<MyClassBE>();
}
Tuttavia, quando passo una lista vuota al metodo, ottengo questo errore:
System.NullReferenceException:. Il riferimento non impostato a un'istanza di un oggetto
dello stack trace Server:
a NHibernate.Engine.TypedValue..ctor (tipo IType, Object value, EntityMode entityMode) in C: \ giunzioni \ BS \ 3rdParty \ NHibernate.2.1.2.GA-src \ src \ NHibernate \ Engine \ TypedValue. cs: linea 25
a NHibernate.Impl.AbstractQueryImpl.SetParameterList (String name, vals ICollection, tipo IType) in C: \ giunzioni \ BS \ 3rdparty \ NHibernate.2.1.2.GA-src \ src \ NHibernate \ Impl \ AbstractQueryImpl.cs : linea 647
a NHibernate.Impl.AbstractQueryImpl.SetParameterList (String name, vals ICollection) in C: \ giunzioni \ BS \ 3rdParty \ NHibernate.2.1.2.GA-src \ src \ NHibernate \ Impl \ AbstractQueryImpl.cs: la linea 666
a MyProject.Dao.MyClassDao.FilterByCategoryID (List`1 categoryIDs) in MyClassDao.cs: linea 50
Quale sarebbe il modo migliore per risolvere questo problema? Si prega di notare che la query di nome è, naturalmente, molto più complicato di quello presentato in precedenza, quindi mi piacerebbe evitare di copiare a una seconda versione che non utilizza l'elenco dei parametri.
Soluzione
Ho appena affrontato lo stesso problema, quindi ho anche se ho bisogno di condividere la soluzione:
Modifica la tua richiesta a:
<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>
E il codice a:
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>();
}
Spiegazione:
- modificare query di ignorare le categorie in cui tale disposizione.
- modificare un parametro aggiuntivo per indicare ( 1 ).
- Aggiungiamo ID casuale che non viene mai utilizzato. Giusto per assicurarsi che il in istruzione SQL è valido.
Quindi questo modo è possibile mantenere la vostra query complessa e basta aggiungere parametri aggiuntivi ad esso.
svantaggio evidente è che si passa il parametro inutile.
Ma fa il lavoro.
Altri suggerimenti
Credo che si può evitare tale errore utilizzando Cast
di .NET
return session.GetNamedQuery("MyClass_FilterByCategoryID")
.SetParameterList("categoryIDs", categoryIDs)
.List().Cast<MyClassBE>();
che dovrebbe restituire un elenco vuoto, non è un'eccezione.
test se la lista è vuota e fare qualcosa di diverso. in questo particolare query che si desidera tutto il MyClassBE che non sono nei ID di categoria che significa tutti loro:
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>();
}