2009-10-09 7 views
10

J'écris une routine C# pour appeler un proc stocké. Dans la liste de paramètres que je passe, il est possible que l'une des valeurs puisse légalement être nulle. Donc, je pensais que j'utiliser une ligne comme celui-ci:Est-il possible de fusionner string et DBNull en C#?

cmd.Parameters.Add(new SqlParameter("@theParam", theParam ?? DBNull.Value)); 

Malheureusement, cela renvoie l'erreur suivante:

CS0019: Operator '??' cannot be applied to operands of type 'string' and 'System.DBNull'

Maintenant, cela semble assez clair, mais je ne comprends pas la raison d'être il. Pourquoi cela ne fonctionnerait-il pas? (Et souvent, quand je ne comprends pas pourquoi quelque chose ne fonctionne pas, ce n'est pas que ça ne fonctionne pas ... c'est que je me trompe.)

Dois-je vraiment étirer cela dans une déclaration si-alors plus long? En outre, pour ceux qui suggèrent d'utiliser simplement "null" tel quel, cela ne fonctionne pas.Je pensais à l'origine que null serait traduit automatiquement en DBNull, mais il ne semble pas. Qui savait?))

Répondre

16

Pas comme ça, non. Les types doivent correspondre. La même chose est vraie pour le ternaire. Maintenant, par "match", je ne veux pas dire qu'ils doivent être les mêmes. Mais ils doivent être compatibles avec les affectations. Fondamentalement: dans le même arbre d'héritage.

Une façon de contourner cela est de lancer votre chaîne à l'objet:

var result = (object)stringVar ?? DBNull.Value; 

Mais je n'aime pas cela, parce que cela signifie que vous appuyer davantage sur le constructeur SqlParameter pour obtenir vos bons types . Au lieu de cela, j'aime faire comme ceci:

cmd.Parameters.Add("@theParam", SqlDbTypes.VarChar, 50).Value = theParam; 
// ... assign other parameters as well, don't worry about nulls yet 

// all parameters assigned: check for any nulls 
foreach (var p in cmd.Parameters) 
{ 
    if (p.Value == null) p.Value = DBNull.Value; 
} 

Notez également que j'ai explicitement déclaré le type de paramètre.

+0

Pour l'information, les commandes créées par un CommandBuilder ont un ensemble des paramètres construits pour vous. Cependant, le même problème se pose en ce que vous ne pouvez pas vous attendre à passer null à l'un des paramètres dans le ParameterCollection généré. vous devez encore faire comme décrit ci-dessus. – rohancragg

+0

Belle solution simple :-) – IrishChieftain

+0

Vous pouvez également créer une méthode d'extension pour ce faire. –

0

Je suis à peu près sûr que le simple fait de passer une valeur nulle au constructeur SqlParameter a pour résultat qu'il est envoyé en tant que DBNull.Value ... Je peux me tromper, puisque j'utilise l'EnterpriseLibraries pour l'accès DB, mais je suis sûr que l'envoi d'un null est bien là.

+2

Oui, vous avez tort, -1. Si vous tentez simplement de passer la valeur null, SQL Server affichera une erreur "le paramètre ... n'existe pas". – erikkallen

+0

Erich, je suppose que vous avez raison sur celui-ci comme j'ai observé le comportement que vous décrivez plusieurs fois dans VB.NET. Mis à part le fait qu'il s'agit de C#, je ne sais pas quelles sont les autres circonstances qui lui permettent de travailler pour moi et non pour erikkallen ou Beska. –

+0

Ah, j'utilise habituellement la classe SqlHelper et je viens de trouver cette ligne à l'intérieur: Si (p.Direction = ParameterDirection.InputOutput OrElse p.Direction = ParameterDirection.Input) EtAlso p.Value est Nothing Then p.Value = DBNull .Valeur Fin Si ... Voilà pourquoi cela fonctionne. –

-1

Vous ne savez pas exactement la réponse à votre question, mais qu'en est-il de cela?

string.IsNullOrEmpty(theParam) ? DBNull.Value : theParam 

ou si elle est vide est ok

(theParam == null) ? DBNull.Value : theParam 
+1

Noth- ternary requiert également que les types correspondent. –

+0

D'oh! Ça va m'apprendre à post-tester! – n8wrl

5
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value) 
+0

Vous n'avez même pas besoin de les convertir tous les deux en null. Je fais d'habitude nouveau SqlParameter ("@ theParam", (objet) theParam ?? DBNull.Value) – erikkallen

3

Le ?? L'opérateur renvoie l'opérande de gauche s'il n'est pas nul, ou bien il renvoie l'opérande de droite. Mais dans votre cas, ils sont de types différents, donc ça ne marche pas.

+0

(édition sans conséquence faite de sorte qu'il me laisserait voter cette réponse vers le haut.) – Beska

0

cmd.Parameters.Add (nouveau SqlParameter ("@ theParam", (theParam == null)? DBNull.Value: theParam));

2

La raison pour laquelle vous ne pouvez pas utiliser l'opérateur null coalesce est qu'il doit renvoyer un type et que vous fournissez plusieurs types. theParam est une chaîne. DbNull.Value est une référence à une instance statique de type System.DbNull. C'est à quoi ressemble sa mise en œuvre;

public static readonly DBNull Value = new DBNull(); 
//the instantiation is actually in the 
//static constructor but that isn't important for this example 

Donc, si vous deviez avoir une méthode de NullCoalesce, quel serait son type de retour? Il ne peut pas être à la fois System.String et System.DbNull, il doit être l'un ou l'autre, ou un type parent commun.

Donc, cela conduit à ce type de code;

cmd.Parameters.Add(
    new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 
); 
2

L'opérateur Null Coalesce uniquement avec des données du même type. Vous ne pouvez pas envoyer NULL à SqlParamater, car Sql Server indique que vous n'avez pas spécifié le paramètre.

Vous pouvez utiliser

new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 

Ou vous pouvez créer une fonction qui retourne DBNull lorsque null se trouve, comme

public static object GetDataValue(object o) 
{ 
    if (o == null || String.Empty.Equals(o)) 
     return DBNull.Value; 
    else 
     return o; 
} 

Et puis appelez

new SqlParameter("@theParam", GetDataValue(theParam)) 
+4

Oui, la méthode GetDataValue est comment j'ai géré cela dans le passé. Je souhaite vraiment qu'il y ait un comportement intégré pour cela. Comme une propriété que vous pourriez spécifier sur les classes ADO.NET, cela remplacerait DBNULL.Value (ou quelque chose que vous spécifiez) quand il obtient une valeur nulle. – LoveMeSomeCode

+0

Oui, moi aussi j'aimerais pouvoir spécifier null et le mapper automatiquement à DBNull. –

+0

@LoveMe: Comptez-moi pour cela devrait être géré par défaut! –

0

Utilisez cette syntaxe:

(theParam comme objet) ?? (DBNull.Value comme objet)

Dans ce cas, les deux parties de l'opérateur ?? sont du même type.

+0

1) Vous avez seulement besoin de jeter un côté, les deux sont exagérés; 2) L'utilisation de 'as 'à moins que vous ne vérifiiez la valeur de retour de la distribution (c.-à-d. Comme typewitch) est une mauvaise idée - une distribution normale communique l'effacement d'intention. –

1

Dans votre proc stocké lorsque vous déclarez la variable d'entrée, l'ont mis le var égal à null et ne passent pas dans de votre code csharp, il sera alors ramasser la valeur par défaut de SQL

@theParam as varchar(50) = null 

puis dans votre csharp

if (theParam != null) 
    cmd.Parameters.Add(new SqlParameter("@theParam", theParam)); 

Voici comment je passe habituellement l'option et/ou des valeurs par défaut à mes procs stockées

+0

Je pense que vous vouliez dire "! =", Vous avez fixé un échantillon. –

+0

oui, merci. Je l'ai remarqué pendant que j'essayais de faire fonctionner le bloc de code et j'ai oublié d'y revenir et de le modifier. –

Questions connexes