2009-06-23 19 views
31

estoy usando NHibernate y llamar a un procedimiento almacenado a través de una consulta con nombre:¿Cómo se pueden establecer los valores tipados de valores C# en NHibernate con los parámetros IQuery?

<sql-query name="SearchStuff" read-only="true" cacheable="true"> 
    <return class="ResultEntity" /> 
    EXEC [SearchStuff] ?, ?, ? </sql-query> 

Muchos de los parámetros de procedimiento almacenado son deliberadamente anulable - esto no se puede cambiar.

El C#:

IQuery listQuery = this.Session.GetNamedQuery("SearchStuff"); 
listQuery.SetInt32(0, param1); 
listQuery.SetDateTime(1, param2); 
listQuery.SetString(2, param3); 
IList<ResultEntity> results = listQuery.List<ResultEntity>(); 

Desafortunadamente, NHibernate no proporciona ninguna SetXyz() métodos para los tipos de valor anulables así que traté de añadir algunos métodos de extensión para compensar:

public static class QueryExtensions 
{ 
    public static void SetInt32(this IQuery query, int position, int? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetInt32(position, val.Value); 
     } 
     else 
     { 
      query.SetParameter(position, null); 
     } 
    } 

    public static void SetInt32(this IQuery query, string name, int? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetInt32(name, val.Value); 
     } 
     else 
     { 
      query.SetParameter(name, null); 
     } 
    } 

    public static void SetDateTime(this IQuery query, int position, DateTime? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetDateTime(position, val.Value); 
     } 
     else 
     { 
      query.SetParameter(position, null); 
     } 
    } 

    public static void SetDateTime(this IQuery query, string name, DateTime? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetDateTime(name, val.Value); 
     } 
     else 
     { 
      query.SetParameter(name, null); 
     } 
    } 
} 

He intentado varias versiones de estos, pero ninguno funciona. El código anterior produce el error:

System.ArgumentNullException : A type specific Set(position, val) should be called because the Type can not be guessed from a null value. 

También probé simplemente no estableciendo el parámetro pero NHibernate requiere que cada parámetro que desea ajustar. Intenté usar versiones posicionales y nominales con los mismos resultados.

¿Hay alguna manera de asignar valores nulos a los parámetros de tipo de valor en NHibernate consultas con nombre?

Respuesta

50

OK, resulta que hay algunas sustituciones en SetParameter que permiten establecer el tipo de forma explícita. Por ejemplo:

query.SetParameter(position, null, NHibernateUtil.Int32); 

Los métodos de extensión completa (por Int32 y DateTime solamente) son ahora:

public static class QueryExtensions 
{ 
    public static void SetInt32(this IQuery query, int position, int? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetInt32(position, val.Value); 
     } 
     else 
     { 
      query.SetParameter(position, null, NHibernateUtil.Int32); 
     } 
    } 

    public static void SetInt32(this IQuery query, string name, int? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetInt32(name, val.Value); 
     } 
     else 
     { 
      query.SetParameter(name, null, NHibernateUtil.Int32); 
     } 
    } 

    public static void SetDateTime(this IQuery query, int position, DateTime? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetDateTime(position, val.Value); 
     } 
     else 
     { 
      query.SetParameter(position, null, NHibernateUtil.DateTime); 
     } 
    } 

    public static void SetDateTime(this IQuery query, string name, DateTime? val) 
    { 
     if (val.HasValue) 
     { 
      query.SetDateTime(name, val.Value); 
     } 
     else 
     { 
      query.SetParameter(name, null, NHibernateUtil.DateTime); 
     } 
    } 
} 
+0

Gracias por eso, me ayude :) – RhysC

+3

Si devuelve el objeto de consulta de los métodos que también consigue el, por ejemplo correcto encadenamiento: pública IQuery SetDateTime estática (... ... consulta retrun; –

+0

extensiones sólidas ! –

3

Los métodos de extensión completa (por Int32 y sólo DateTime) con encadenamiento son ahora:

public static class QueryExtensions 
{ 
    public static IQuery SetInt32(this IQuery __query, int __position, int? __val) 
    { 
     var _query = __val.HasValue ? __query.SetInt32(__position, __val.Value) : __query.SetParameter(__position, null, NHibernateUtil.Int32); 

     return _query; 
    } 

    public static IQuery SetInt32(this IQuery __query, string __name, int? __val) 
    { 
     var _query = __val.HasValue ? __query.SetInt32(__name, __val.Value) : __query.SetParameter(__name, null, NHibernateUtil.Int32); 

     return _query; 
    } 

    public static IQuery SetDateTime(this IQuery __query, int __position, DateTime? __val) 
    { 
     var _query = __val.HasValue ? __query.SetDateTime(__position, __val.Value) : __query.SetParameter(__position, null, NHibernateUtil.DateTime); 

     return _query; 
    } 

    public static IQuery SetDateTime(this IQuery __query, string __name, DateTime? __val) 
    { 
     var _query = __val.HasValue ? __query.SetDateTime(__name, __val.Value) : __query.SetParameter(__name, null, NHibernateUtil.DateTime); 

     return _query; 
    } 
} 
+0

Gracias, rbrock, por esta adición a las extensiones anteriores. Esto es exactamente lo que necesitaba :) –

10

Otra forma de lograrlo es:

query.SetParameter<int?>(0, null); 
query.SetParameter<DateTime?>(1, null); 
... 

Y así sucesivamente ...

Observe el símbolo ? que hace que el tipo primitivo se pueda anular.

Cuestiones relacionadas