SqlParameterにnullを割り当てる


188

次のコードは、「DBnullから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;

4
あなたは私が考えるオブジェクトへAgeItem.AgeIndexをキャストする必要があります... stackoverflow.com/questions/202271/...を (ところで、なぜ==3行目の末尾に?)
グレッグ

回答:


341

問題は、互換性のない値またはDBNull型の値を?:返すため、演算子が戻り値の型を判別できないことですint

もちろん、AgeIndexのインスタンスobjectを、?:要件を満たすタイプにキャストできます。

??次のようにnull結合演算子を使用できます。

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

これは、問題を説明するオペレーター向けのMSDNドキュメントからの引用です?:

first_expressionとsecond_expressionのタイプが同じであるか、1つのタイプから別のタイプへの暗黙の変換が存在する必要があります。


nullをオブジェクトにキャストしようとしたときに例外がスローされないのはなぜですか?私はそれがあるべきだと思いますAgeItem.AgeIndex as object
Niels Brinch

@Niels Brinch、nullはオブジェクトなので例外はありません。nullを逆参照しない限り、完全に合法です。ただし、この例では、オブジェクトにキャストされているのはnullではなく、実際には値の型であるDBNull.Valueです。?? オペレーターは、「AgetItem.AgeIndexがnullの場合はDBNull.Valueを返し、それ以外の場合はAgeItem.AgeIndexを返却する」と言い、応答はオブジェクトにキャストされます。詳細については、null結合演算子を参照してください。msdn.microsoft.com/en-us/library/ms173224.aspx
Chris Taylor

3
技術的には、null-coalescing演算子??を使用するソリューションは、通常の三項を使用する場合と同じソリューション?:です。それでもAgeItem.AgeIndexオブジェクトにキャストする必要がありますplanIndexParameter.Value = AgeItem.AgeIndex.HasValue ? (object)AgeItem.AgeIndex : DBNull.Value;
newfurniturey 2013

通常の三項を使用?:して型固有の比較を行う場合、式全体をキャストしても機能しません。あなたのようなので、非はDBNullパラメータをキャストする必要があります:someID == 0 ? DBNull.Value : (object)someID
ingredient_15939

これは真実ですが、結果としてSqlParameterを消費する関数の入り口パラメーターとしてnull可能値を使用する必要があり、それがnullの場合、エラーが発生し、この方法は機能せず、単純なIf-Else方法を使用する必要があります。例:sample.Text.Trim()!= ""?func(sample.Text):DBNull.Value; ?:および??として機能しません
QMaster

102

受け入れられた答えは、キャストを利用することを示唆しています。ただし、ほとんどのSQLタイプには、このキャストを回避するために使用できる特殊なNullフィールドがあります。

たとえば、SqlInt32.Null「SqlInt32クラスのこのインスタンスに割り当てることができるDBNullを表します。」

int? example = null;
object exampleCast = (object) example ?? DBNull.Value;
object exampleNoCast = example ?? SqlInt32.Null;

2
提案は有望に見えたので、「System.Data.SqlTypes.SqlString.Null」を試してみましたが、機能しません。「Null」の実際の文字列(「N」、「u」、「l」、「l」)をフィールドに入力し、true(null)で空白のままにします。ただし、(オブジェクト)でのキャストを使用する古い2010年の「受け入れられた答え」は?? DBNull.Valueは正しく機能します。(私が使用したADO.NETプロバイダーはSQLiteでしたが、それが違いを生むかどうかはわかりません。)ブライアンのヒントを注意深くテストして、null動作が期待どおりに機能することを確認することをお勧めします。
JasDev

6
@JasDev:私は漠然とこのトリックを高レプユーザー(Marc Gravellと思う)へのコメントで説明し、それがMicrosoft SQL Serverでのみ機能することを告げられたことを思い出します。
ブライアン、

@JasDevプロバイダーは、ブレインが指摘しているように、これがSQL Serverで機能する違いになります。
Lankymart 2016年

この回答は、オブジェクトへの明示的なキャストを暗黙的なものに置き換えるだけです。サンプルコードでexampleNoCastは、がオブジェクトとして宣言されているため、オブジェクトへのキャストは引き続き発生します。OPのコードのように、値がオブジェクトタイプでもあるSqlParameter.Valueに直接割り当てられている場合でも、キャストを取得できます。
スコット

31

DBNull.Valueストアドプロシージャ内でデフォルト値が指定されていない限り(ストアドプロシージャを使用している場合)、SQLCommand内でnullパラメータとして渡す必要があります。最善の方法は、DBNull.Valueクエリを実行する前に欠落しているパラメーターを割り当てることです。これにより、foreachが実行されます。

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

それ以外の場合は、次の行を変更します。

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

次のように:

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

DBNullとintは互いに異なるため、条件付きステートメントでは異なるタイプの値を使用できないためです。これがお役に立てば幸いです。


この回答は、あらゆる方法で例を示しているので、本当に素晴らしいです。私は最初のアプローチが好きです。通常はEFを使用しますが、この要件ではそれができず、時間を大幅に節約できます。ありがとう!
Leandro

23

1行のコードで、これを試してください:

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

5

これを試して:

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;

5

条件付き(三項)演算子を使用する場合、コンパイラーは両方のタイプ間の暗黙的な変換を必要とします。それ以外の場合は、例外が発生します。

したがって、両方にキャストすることで修正できますSystem.Object

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

しかし、結果は本当にきれいではなく、常にこのキャストを覚えておかなければならないので、代わりにそのような拡張メソッドを使うことができます:

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;
}

次に、この簡潔なコードを使用できます。

planIndexParameter.Value = AgeItem.AgeIndex.GetDBNullOrValue();

1

私の意見では、より良い方法は、SqlCommandクラスのParametersプロパティを使用してこれを行うことです。

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

しかし、値がDBNull.Valueである場合、ADO.NETはSqlDbTypeが何であるかを推測するのに多少苦労するかもしれません........これは便利ですが、少し危険です...
marc_s

1

利用可能なNullable(T)構造の使用を検討してください。値が設定されている場合にのみ値を設定でき、SQLコマンドオブジェクトはnull許容値を認識し、それに応じて煩わしさなく処理されます。


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;
}

0

これを試して:

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

言い換えると、パラメータがnullの場合、それをストアドプロシージャに送信しないでください(もちろん、ストアドプロシージャが質問で暗黙的なnullパラメータを受け入れると仮定します)。


しかし、今、あなたはパラメータを省略しているだけです-ストアドプロシージャがこれについて満足していることを私は強く疑っています。 。
marc_s

ワオ。厳しい。パラメータが渡されない場合(@AgeIndex int = 0)は、ストアドプロシージャをデフォルトの値に書き込むだけです。いつも起こります。クライアントはデフォルトを受け入れるか、パラメーターを渡してデフォルトをオーバーライドできます。なぜ反対票か。
フリップスター

0

次のようなものを試してください:

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;
}

0
int? nullableValue = null;
object nullableValueDB
{
   get{
       if(nullableValue==null)
          return DBNull.Value;
       else
          return (int)nullableValue;
   }
}

私はそのように解決しています。


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

0

これは私が単に行うことです...

        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();

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");

0

このための簡単な拡張メソッドは次のとおりです。

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

0

nullチェックを使用する単純なメソッドを使用します。

    public SqlParameter GetNullableParameter(string parameterName, object value)
    {
        if (value != null)
        {
            return new SqlParameter(parameterName, value);
        }
        else
        {
            return new SqlParameter(parameterName, DBNull.Value);
        }
    }

1
その条件付きロジックは逆ですか?DBNull.Valueは最初のものにする必要がありますか?
Mark Schultheiss、2018年

確かです。修繕。ありがとう。
Zhi An、

0

私のコードは、実際のプロジェクトで機能しています。三項演算子を見てから、sqlparameterを問題なく、これが私にとって最良の方法です。

    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);
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.