Attribuer null à un SqlParameter

189

Le code suivant donne une erreur - "Aucune conversion implicite de DBnull en int."

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;
parameters[0] = planIndexParameter;
Relativité
la source
4
Vous devez lancer AgeItem.AgeIndex en objet, je pense ... stackoverflow.com/questions/202271/… (btw, pourquoi le ==à la fin de la 3ème ligne?)
Greg

Réponses:

341

Le problème est que l' ?:opérateur ne peut pas déterminer le type de retour car vous retournez unint valeur ou une valeur de type DBNull, qui ne sont pas compatibles.

Vous pouvez bien sûr convertir l'instance d'AgeIndex en un type objectqui satisferait l' ?:exigence.

Vous pouvez utiliser l' ??opérateur de fusion nul comme suit

SqlParameter[] parameters = new SqlParameter[1];     
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
planIndexParameter.Value = (object)AgeItem.AgeIndex ?? DBNull.Value;
parameters[0] = planIndexParameter; 

Voici une citation de la documentation MSDN pour l' ?:opérateur qui explique le problème

Soit le type de first_expression et second_expression doit être le même, soit une conversion implicite doit exister d'un type à l'autre.

Chris Taylor
la source
Pourquoi n'y a-t-il aucune exception levée lors de la tentative de conversion de null en objet? Je pense que ça devrait êtreAgeItem.AgeIndex as object
Niels Brinch
@Niels Brinch, il n'y aurait pas d'exception car null est un objet et tant que vous n'essayez pas de le déréférencer, c'est parfaitement légal. Cependant, dans cet exemple, il n'est pas nul en cours de conversion en objet, il s'agit de DBNull.Value qui est en fait un type valeur. Le ?? L'opérateur dit «si AgetItem.AgeIndex est nul, alors renvoie DBNull.Value sinon returen AgeItem.AgeIndex», la réponse est convertie en objet. Voir l'opérateur de fusion nul pour plus de détails. msdn.microsoft.com/en-us/library/ms173224.aspx
Chris Taylor
3
Techniquement, votre solution en utilisant l'opérateur null coalescent ??est la même solution que si vous deviez utiliser le ternaire régulière ?:- vous avez encore besoin de plâtre AgeItem.AgeIndexà un objet: planIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;.
newfurniturey
Si vous deviez utiliser le ternaire régulier ?:pour effectuer une comparaison spécifique au type, la conversion de l'expression entière ne fonctionnera pas. Vous devez transtyper le paramètre non-dbnull comme ceci:someID == 0 ? DBNull.Value : (object)someID
ingrédient_15939
C'est vrai, mais si vous avez besoin d'utiliser la valeur null-able comme paramètre d'entrée de la fonction, le résultat consomme SqlParameter et s'il est nul, vous obtenez une erreur de cette façon ne fonctionne pas et vous devez utiliser simplement la méthode If-Else simple. par exemple: sample.Text.Trim ()! = ""? func (sample.Text): DBNull.Value; ne fonctionnera pas comme?: et ??
QMaster
105

La réponse acceptée suggère d'utiliser un plâtre. Cependant, la plupart des types SQL ont un champ Null spécial qui peut être utilisé pour éviter cette conversion.

Par exemple, SqlInt32.Null«représente un DBNull qui peut être affecté à cette instance de la classe SqlInt32».

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;
Brian
la source
2
La suggestion avait l'air prometteuse alors j'ai essayé "System.Data.SqlTypes.SqlString.Null" mais cela ne fonctionne pas. Il place la chaîne réelle de "Null" ('N', 'u', 'l', 'l') dans le champ au lieu de le laisser vide avec true (null). Cependant, l'ancienne "réponse acceptée" de 2010 qui utilise le cast avec (objet) ?? DBNull.Value fonctionne correctement. (Le fournisseur ADO.NET que j'ai utilisé était SQLite, mais je ne suis pas sûr que cela fasse une différence.) Je suggère que d'autres testent attentivement le conseil de Brian pour s'assurer que le comportement nul fonctionne comme prévu.
JasDev
6
@JasDev: Je me souviens vaguement d'avoir décrit cette astuce dans un commentaire à un utilisateur de haute réputation (je pense que Marc Gravell) et m'être dit que cela ne fonctionne que sur Microsoft SQL Server.
Brian
@JasDev le fournisseur sera la différence que cela fonctionne dans SQL Server comme le souligne Brain.
Lankymart
Cette réponse remplace uniquement un cast explicite en objet par un implicit.one. Dans l'exemple de code, exampleNoCastest déclaré objet, de sorte que la conversion en objet se produit toujours. Si, comme dans le code de l'OP, la valeur est affectée directement à SqlParameter.Value qui est également de type object, alors vous obtenez toujours le cast.
Scott
31

Vous devez passer en DBNull.Valuetant que paramètre nul dans SQLCommand, sauf si une valeur par défaut est spécifiée dans la procédure stockée (si vous utilisez une procédure stockée). La meilleure approche consiste à attribuer DBNull.Valuetout paramètre manquant avant l'exécution de la requête, et le fait de suivre foreach fera l'affaire.

foreach (SqlParameter parameter in sqlCmd.Parameters)
{
    if (parameter.Value == null)
    {
        parameter.Value = DBNull.Value;
    }
}

Sinon, modifiez cette ligne:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex;

Comme suit:

if (AgeItem.AgeIndex== null)
    planIndexParameter.Value = DBNull.Value;
else
    planIndexParameter.Value = AgeItem.AgeIndex;

Parce que vous ne pouvez pas utiliser différents types de valeurs dans une instruction conditionnelle, car DBNull et int sont différents l'un de l'autre. J'espère que cela aidera.

ShahidAzim
la source
Cette réponse est vraiment sympa car elle donne des exemples de toutes les manières possibles. J'aime la première approche, j'utilise habituellement EF mais dans cette exigence je ne pourrais pas le faire et cela me fait gagner beaucoup de temps. Merci!
Leandro
23

Avec une ligne de code, essayez ceci:

var piParameter = new SqlParameter("@AgeIndex", AgeItem.AgeIndex ?? (object)DBNull.Value);
Adrian
la source
5

Essaye ça:

SqlParameter[] parameters = new SqlParameter[1];    
SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);

planIndexParameter.IsNullable = true; // Add this line

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex== ;
parameters[0] = planIndexParameter;
décyclone
la source
5

Si vous utilisez l'opérateur conditionnel (ternaire), le compilateur a besoin d'une conversion implicite entre les deux types, sinon vous obtenez une exception.

Vous pouvez donc résoudre ce problème en lançant l'un des deux vers System.Object:

planIndexParameter.Value = (AgeItem.AgeIndex== null) ? DBNull.Value : (object) AgeItem.AgeIndex;

Mais comme le résultat n'est pas vraiment joli et que vous devez toujours vous souvenir de ce casting, vous pouvez utiliser une telle méthode d'extension à la place:

public static object GetDBNullOrValue<T>(this T val)
{
    bool isDbNull = true;
    Type t = typeof(T);

    if (Nullable.GetUnderlyingType(t) != null)
        isDbNull = EqualityComparer<T>.Default.Equals(default(T), val);
    else if (t.IsValueType)
        isDbNull = false;
    else
        isDbNull = val == null;

    return isDbNull ? DBNull.Value : (object) val;
}

Ensuite, vous pouvez utiliser ce code concis:

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();
Tim Schmelter
la source
1

À mon avis, le meilleur moyen est de le faire avec la propriété Parameters de la classe SqlCommand :

public static void AddCommandParameter(SqlCommand myCommand)
{
    myCommand.Parameters.AddWithValue(
        "@AgeIndex",
        (AgeItem.AgeIndex== null) ? DBNull.Value : AgeItem.AgeIndex);
}

la source
Mais si la valeur est DBNull.Value, ADO.NET pourrait avoir un peu de mal à deviner quel SqlDbType cela pourrait être ........ c'est pratique - mais un peu dangereux ....
marc_s
1

Pensez à utiliser la structure Nullable (T) disponible. Cela vous permettra de définir des valeurs uniquement si vous les avez, et vos objets de commande SQL reconnaîtront la valeur Nullable et traiteront en conséquence sans tracas de votre part.

Kanwar Singh
la source
1
if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}
Anil kumar
la source
0

Essaye ça:

if (AgeItem.AgeIndex != null)
{
   SqlParameter[] parameters = new SqlParameter[1];
   SqlParameter planIndexParameter = new SqlParameter("@AgeIndex", SqlDbType.Int);
   planIndexParameter.Value = AgeItem.AgeIndex;
   parameters[0] = planIndexParameter;
}

En d'autres termes, si le paramètre est nul, ne l'envoyez pas à votre proc stocké (en supposant, bien sûr, que le proc stocké accepte des paramètres nuls qui sont implicites dans votre question).

Flipster
la source
Mais maintenant, vous omettez simplement un paramètre - je doute fortement que la procédure stockée soit satisfaite de cela .... très probablement, l'appel échouera en indiquant "aucune valeur pour le paramètre @AgeIndex fournie qui était attendue" .... .
marc_s
Sensationnel. Dur. Il suffit d'écrire le processus stocké sur une valeur par défaut si le paramètre n'est pas passé (@AgeIndex int = 0). Arrive tout le temps. Le client peut accepter la valeur par défaut ou la remplacer en passant le paramètre. Pourquoi le vote négatif?
Flipster
0

essayez quelque chose comme ça:

if (_id_categoria_padre > 0)
{
    objComando.Parameters.Add("id_categoria_padre", SqlDbType.Int).Value = _id_categoria_padre;
}
else
{
    objComando.Parameters.Add("id_categoria_padre", DBNull.Value).Value = DBNull.Value;
}
user2574441
la source
0
int? nullableValue = null;
object nullableValueDB
{
   get{
       if(nullableValue==null)
          return DBNull.Value;
       else
          return (int)nullableValue;
   }
}

Je résous comme ça.

Un Sinan Direk
la source
0
if (AgeItem.AgeIndex== null)  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = DBNull);  
else  
    cmd.Parameters.Add(new SqlParameter("ParaMeterName", SqlDbType.DateTime).Value = AgeItem.AgeIndex);
Anil kumar
la source
0

C'est ce que je fais simplement ...

        var PhoneParam = new SqlParameter("@Phone", DBNull.Value);
        if (user.User_Info_Phone != null)
        {
            PhoneParam.SqlValue = user.User_Info_Phone;
        }

        return this.Database.SqlQuery<CustLogonDM>("UpdateUserInfo @UserName, @NameLast, @NameMiddle, @NameFirst, @Address, @City, @State, @PostalCode, @Phone",
            UserNameParam, NameLastParam, NameMiddleParam, NameFirstParam, AddressParam, CityParam, StateParam, PostalParam, PhoneParam).Single();
Tom Mack
la source
0
            dynamic psd = DBNull.Value;

            if (schedule.pushScheduleDate > DateTime.MinValue)
            {
                psd = schedule.pushScheduleDate;
            }


            sql.DBController.RunGeneralStoredProcedureNonQuery("SchedulePush",
                     new string[] { "@PushScheduleDate"},
                     new object[] { psd }, 10, "PushCenter");
papapa
la source
0

Une méthode d'extension simple pour cela serait:

    public static void AddParameter(this SqlCommand sqlCommand, string parameterName, 
        SqlDbType sqlDbType, object item)
    {
        sqlCommand.Parameters.Add(parameterName, sqlDbType).Value = item ?? DBNull.Value;
    }
marque
la source
0

J'utilise une méthode simple avec une vérification nulle.

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }
Zhi An
la source
1
Est-ce que cette logique conditionnelle est à l'envers? DBNull.Value doit-il être dans le premier?
Mark Schultheiss
Sûrement. Fixé. Merci.
Zhi An
0

Mon code, travaillant dans un projet réel Regardez l'opérateur ternaire avant de définir le paramètre sql, c'est le meilleur moyen pour moi, sans problèmes:

    public bool Key_AddExisting
    (
          string clave
        , int? idHito_FileServer
        , int? idTipoDocumental_Almacen
        , string tipoExp_CHJ
        , int idTipoExp_Verti2
        , int idMov_Verti2
    )
    {
        List<SqlParameter> pars = new List<SqlParameter>()
        {
              new SqlParameter { ParameterName = "@Clave", Value = clave }
    LOOK -> , idHito_FileServer == null ? new SqlParameter { ParameterName = "@IdHito_FileServer", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdHito_FileServer", Value = idHito_FileServer }
    LOOK -> , idTipoDocumental_Almacen == null ? new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = DBNull.Value } : new SqlParameter { ParameterName = "@IdTipoDocumental_Almacen", Value = idTipoDocumental_Almacen }
            , new SqlParameter { ParameterName = "@TipoExp_CHJ", Value = tipoExp_CHJ }
            , new SqlParameter { ParameterName = "@IdTipoExp_Verti2", Value = idTipoExp_Verti2 }
            , new SqlParameter { ParameterName = "@IdMov_Verti2", Value = idMov_Verti2 }
        };

        string sql = "INSERT INTO [dbo].[Enlaces_ClavesCHJ_MovimientosVerti2] " +
            "( " +
            "  [Clave] " +
            ", [IdHito_FileServer] " +
            ", [IdTipoDocumental_Almacen] " +
            ", [TipoExp_CHJ] " +
            ", [IdTipoExp_Verti2] " +
            ", [IdMov_Verti2] " +
            ") " +
            "VALUES" +
            "( " +
            "  @Clave" +
            ", @IdHito_FileServer" +
            ", @IdTipoDocumental_Almacen" +
            ", @TipoExp_CHJ" +
            ", @IdTipoExp_Verti2" +
            ", @IdMov_Verti2" +
            ")";

        return DbBasic.ExecNonQuery(ref this.conn, sql, pars);
    }
Ángel Ibáñez
la source