2010-04-08 10 views
27

Me cansé de escribir el siguiente código:¿Cómo parametrizar una cadena nula con DBNull.Value clara y rápidamente

/* Commenting out irrelevant parts 
public string MiddleName; 
public void Save(){ 
    SqlCommand = new SqlCommand(); 
    // blah blah...boring INSERT statement with params etc go here. */ 
    if(MiddleName==null){ 
     myCmd.Parameters.Add("@MiddleName", DBNull.Value); 
    } 
    else{ 
     myCmd.Parameters.Add("@MiddleName", MiddleName); 
    } 
    /* 
    // more boring code to save to DB. 
}*/ 

Así, escribí esto:

public static object DBNullValueorStringIfNotNull(string value) 
{ 
    object o; 
    if (value == null) 
    { 
     o = DBNull.Value; 
    } 
    else 
    { 
     o = value; 
    } 
    return o; 
} 

// which would be called like: 
myCmd.Parameters.Add("@MiddleName", DBNullValueorStringIfNotNull(MiddleName)); 

Si esto es una buena forma de hacerlo, ¿qué sugieres como nombre del método? DBNullValueorStringIfNotNull es un poco detallado y confuso.

También estoy abierto a formas de aliviar este problema por completo. ME ENCANTARÍA hacer esto:

myCmd.Parameters.Add("@MiddleName", MiddleName==null ? DBNull.Value : MiddleName); 

pero eso no funcionará porque el "Operador" ?? no se puede aplicar a operandos de tipo 'cadena' y 'System.DBNull' ".

Tengo C# 3.5 y SQL Server 2005 a mi disposición si es importante.

+0

no escribiría la instancia nula en todos - si el valor es nulo, omitir de la instrucción de inserción. –

+0

pero eso no funcionará. - por favor, sea específico, ¿por qué la gente debería adivinar? – Andrey

+1

@Andrey: Su declaración no compilará (el compilador dirá que no hay conversión implícita entre 'DBNull' y' string'). –

Respuesta

47

Emitir cualquiera de sus valores a object y compilará.

myCmd.Parameters.Add("@MiddleName", MiddleName==null ? (object)DBNull.Value : MiddleName); 
+10

Dulce: 'MiddleName ?? (objeto) DBNull.Value' funciona! O mejor aún, 'objeto static readonly público DBNullValue = (object) DBNull.Value;' con 'MiddleName ?? DBNullValue'! Eres mi héroe. –

+0

Argh, tengo que esperar 3 minutos más para poder aceptar tu respuesta. –

+0

@David: ¡Agradable! Ni siquiera había considerado fusionarse. Tendré que empezar a hacer eso en mi código. Pensé en almacenar en caché el valor como describes, pero quería mantener el código en una línea. –

1

Yeap, nos encantaría hacer myCmd.Parameters.Add("@MiddleName", MiddleName ?? DBNull.Value);. O mejor aún, tenga la capa SqlClient freakin 'entender que CLR null se debe mapear a DBNull.Value al agregar un parámetro. Desafortunadamente, el sistema de tipo .Net cierra la primera alternativa y la implementación de SqlClient cierra la segunda.

Iría con un nombre de función bien conocido, como Coalesce o IsNull. Cualquier desarrollador de DB reconocerá lo que hacen en un instante, solo desde el nombre.

+1

Existen buenas razones para que 'null' no se asigne a' DBNull.Value'. A saber, que te obliga a asignar un valor a cada parámetro, incluso si ese "valor" es un valor nulo de la base de datos. –

+0

Además, ¿tienes la capacidad de hacer una cadena? DBNull.Value podría ser bueno para esta circunstancia particular, debe considerar el problema desde la perspectiva del compilador: ¿Cuál es el tipo de retorno de esa expresión? ¿Debería el compilador buscar el antecesor más común, incluso si es 'objeto'? –

+0

Quizás no haya aclarado lo que quiero decir con 'el sistema de tipos CLR': la imposibilidad de establecer el tipo de tiempo de compilación de la expresión '(type1 ?? type2)'. Estamos diciendo lo mismo. –

11

Personalmente esto es lo que haría con un método de extensión (asegurarse de que esto sucede en una clase estática)

public static object GetStringOrDBNull(this string obj) 
{ 
    return string.IsNullOrEmpty(obj) ? DBNull.Value : (object) obj 
} 

entonces tendría

myCmd.Parameters.Add("@MiddleName", MiddleName.GetStringOrDBNull()); 
+0

Me gusta el nombre. Entonces +1 por eso. Sin embargo, me gusta más la solución de la respuesta aceptada. :-) –

+4

Vea si cambia de parecer después de que en lugar de tener 100 declaraciones si tiene 100 operadores ternarios. –

+2

En realidad estoy usando un operador coalescente nulo. Tienes que aceptar que 'MiddleName ?? DBNullValue' es bastante fácil. Pero +1 por tu comentario también. –

1

Yo prefiero darle dos sugerencias totalmente diferentes:

  1. Utilice un ORM. Hay muchas herramientas ORM no intrusivas.

  2. Escribe tu propia envoltura para construir comandos, con una interfaz más limpia.Algo así como:

    public class MyCommandRunner { 
        private SqlCommand cmd; 
    
        public MyCommandRunner(string commandText) { 
        cmd = new SqlCommand(commandText); 
        } 
    
        public void AddParameter(string name, string value) { 
        if (value == null) 
        cmd.Parameters.Add(name, DBNull.Value); 
        else 
         cmd.Parameters.Add(name, value); 
        } 
    
        // ... more AddParameter overloads 
    } 
    

Si cambia el nombre de sus AddParameter métodos para simplemente Add, que se puede utilizar de una manera muy elegante:

var cmd = new MyCommand("INSERT ...") 
    { 
    { "@Param1", null }, 
    { "@Param2", p2 } 
    }; 
+0

+1 para esta idea. Puedo considerar esto en el futuro. –

1

se recomienda usar propiedades con valores nulos en lugar de campos públicos y un método 'AddParameter' (no sé si este código está optimizado o es correcto, solo fuera de mi cabeza):


private string m_MiddleName; 

public string MiddleName 
{ 
    get { return m_MiddleName; } 
    set { m_MiddleName = value; } 
} 

. 
. 
. 

public static void AddParameter(SQLCommand cmd, string parameterName, SQLDataType dataType, object value) 
{ 
    SQLParameter param = cmd.Parameters.Add(parameterName, dataType); 

    if (value is string) { // include other non-nullable datatypes 
    if (value == null) { 
     param.value = DBNull.Value; 
    } else { 
     param.value = value; 
    } 
    } else { 

    // nullable data types 
    // UPDATE: HasValue is for nullable, not object type 
    if (value.HasValue) // {{{===================================================== 
    { 
      param.value = value; 
    } else 
    { 
      param.value = DBNull.Value; 
    } 
    } 
} 

. 
. 
. 
AddParameter(cmd, "@MiddleName", SqlDbType.VarChar, MiddleName); 

+0

value.HasValue no compila: HasValue es para nullable , no tipo de objeto – Kiquenet

2

@David Gracias por su sugerencia. El siguiente método funciona muy bien!

MiddleName ?? (object)DBNull.Value 
14

puede evitar el elenco explícita a object usando SqlString.Null en lugar de DBNull.Value:

MiddleName ?? SqlString.Null 

Hay correspondientes tipos de int, fecha y hora, y así sucesivamente. He aquí un fragmento de código con un par de ejemplos:

cmd.Parameters.AddWithValue("@StartDate", StartDate ?? SqlDateTime.Null); 
cmd.Parameters.AddWithValue("@EndDate", EndDate ?? SqlDateTime.Null); 
cmd.Parameters.AddWithValue("@Month", Month ?? SqlInt16.Null); 
cmd.Parameters.AddWithValue("@FormatID", FormatID ?? SqlInt32.Null); 
cmd.Parameters.AddWithValue("@Email", Email ?? SqlString.Null); 
cmd.Parameters.AddWithValue("@ZIP", ZIP ?? SqlBoolean.Null); 
6
myCmd.Parameters.Add("@MiddleName", MiddleName ?? (object)DBNull.Value); 
Cuestiones relacionadas