2010-04-08 3 views
27

Je suis fatigué d'écrire le code suivant:Comment paramétrer une chaîne vide avec DBNull.Value clairement et rapidement

/* 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. 
}*/ 

Alors, je l'ai écrit ceci:

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 cela est un bon moyen de faire cela alors que suggéreriez-vous comme nom de la méthode? DBNullValueorStringIfNotNull est un peu bavard et déroutant.

Je suis également ouvert aux moyens de résoudre ce problème entièrement. Je voudrais faire ceci:

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

mais cela ne fonctionnera pas parce que le "Opérateur" ?? ne peut pas être appliqué aux opérandes de type 'string et' System.DBNull '". J'ai le C# 3.5 et SQL Server 2005 à ma disposition si cela est important.

+0

Je ne pas écrire l'instance nulle du tout - si la valeur est nulle, omettre de l'instruction d'insertion. –

+0

mais cela ne fonctionnera pas. - S'il vous plaît soyez précis, pourquoi les gens devraient deviner? – Andrey

+1

@Andrey: Sa déclaration ne compilera pas (le compilateur dira qu'il n'y a pas de conversion implicite entre 'DBNull' et' string'). –

Répondre

47

Convertissez l'une de vos valeurs en object et elle sera compilée.

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

Sweet: 'MiddleName ?? (objet) DBNull.Value' fonctionne! Ou mieux encore 'public static readonly object DBNullValue = (objet) DBNull.Value;' avec 'MiddleName ?? DBNullValue'! Tu es mon héros. –

+0

Argh, je dois attendre 3 minutes de plus avant que je puisse accepter votre réponse. –

+0

@David: Sympa! N'avait même pas envisagé de coalescence. Je vais devoir commencer à faire ça dans mon code. J'ai pensé à mettre en cache la valeur que vous décrivez, mais je voulais garder le code à une ligne. –

1

Yeap, nous aimerions tous faire myCmd.Parameters.Add("@MiddleName", MiddleName ?? DBNull.Value);. Ou mieux encore, avez la couche SqlClient freakin 'comprendre que CLR null doit être mappé à DBNull.Value lors de l'ajout d'un paramètre. Malheureusement, le système de type .Net ferme la première alternative et l'implémentation de SqlClient ferme la seconde.

J'irais avec un nom de fonction bien connu, comme Coalesce ou IsNull. Tout développeur de DB reconnaîtra ce qu'il fait en un instant, à partir du nom seul.

+1

Il existe de bonnes raisons pour lesquelles 'null' ne correspond pas à' DBNull.Value'. A savoir qu'il vous oblige à attribuer une valeur à chaque paramètre, même si cette "valeur" est une valeur nulle de la base de données. –

+0

En outre, ayant la capacité de faire de la chaîne ?? DBNull.Value pourrait être agréable pour cette circonstance particulière, vous devez considérer le problème du point de vue du compilateur: Quel est le type de retour de cette expression? Est-ce que le compilateur devrait chercher l'ancêtre le plus commun, même si c'est 'object'? –

+0

Peut-être que je ne veux pas effacer ce que je veux dire par 'le système de type CLR': l'impossibilité d'établir le type de compilation de l'expression '(type1 ?? type2)'. Nous disons la même chose. –

11

Personnellement ce que je ferais avec une méthode d'extension (assurez-vous que ce qui se passe dans une classe statique)

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

Ensuite, vous auriez

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

J'aime le nom. Donc +1 pour ça. J'aime mieux la solution de la réponse acceptée. :-) –

+4

Voyez si vous changez d'avis après avoir remplacé 100 instructions if si vous avez 100 opérateurs ternaires. –

+2

J'utilise actuellement un opérateur de coalescence nulle. Vous devez accepter que «MiddleName ?? DBNullValue' est sacrément facile. Mais +1 pour votre commentaire aussi. –

1

Je préfère vous donner deux suggestions totalement différentes:

  1. Utilisez un ORM. Il y a beaucoup d'outils ORM non intrusifs. Ecrivez votre propre emballage pour les commandes de construction, avec une interface plus propre.Quelque chose comme:

    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 vous Renommez vos méthodes AddParameter juste Add, vous pouvez l'utiliser d'une manière très lisse:

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

+1 pour cette idée. Je peux considérer cela dans le futur. –

1

Je suggère d'utiliser les propriétés nullables au lieu des champs publics et une méthode 'AddParameter' (je ne sais pas si ce code est optimisé ou correct, juste du haut de ma tête):


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

valeur.HasValue ne se compile pas: HasValue est pour nullable , pas le type d'objet – Kiquenet

2

@David Merci pour votre suggestion. La méthode suivante fonctionne très bien!

MiddleName ?? (object)DBNull.Value 
14

Vous pouvez éviter la distribution explicite à l'aide objectSqlString.Null au lieu de DBNull.Value:

MiddleName ?? SqlString.Null 

Il existe plusieurs types correspondants pour int, datetime, et ainsi de suite. Voici un extrait de code avec quelques autres exemples:

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); 
Questions connexes