6

私のコードには例外があります。int64 を int32 に変更しようとしましたが、変更されません。

データベースでは、「column_ID」を表すセルのデータ型は NUMBER です。

問題は、このコードの 7 行目にあります。

private void dataGridView_ArticleINVIA_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex >= 0 && e.RowIndex <= (sender as DataGridView).Rows.Count - 1)
    {
        try
        {
            Int64 id_riga = Convert.ToInt64((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value);
            //Exception thrown here:
            int id_macchina = Convert.ToInt32((sender as 
                DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value);
            FormRecipeNote PopUpNote = new FormRecipeNote(id_macchina, 
                "MODIFICA", id_riga, 0);
            PopUpNote.ShowDialog(this);
            PopUpNote.Dispose();
         }
         catch (Exception Exc)
         {
             FormMain.loggerSoftwareClient.Trace(this.Name + " " + Exc);
         }
         //DataGrid_ArticleINVIA();
    }
}

エラーは次のとおりです。

System.InvalidCastException: Object cannot be cast from DBNull to other types.
   at System.DBNull.System.IConvertible.ToInt64(IFormatProvider provider)
   at System.Convert.ToInt64(Object value)
   at Software_Client.FormSendReceiveRecipe.dataGridView_ArticleINVIA_CellDoubleClick(Object sender, DataGridViewCellEventArgs e)

誰かがこれを解決するのを手伝ってくれますか?

4

3 に答える 3

9

エラーメッセージが示すように、セルの値は であり、DBNull.Valueそれから希望する値 (この場合は alongまたはint) に変換できません。DBNull数値を変換/キャストする前に確認する必要があります。

Int64 id_riga = 0;
object value = (sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value;
if(value != DBNull.Value) 
    id_riga = Convert.ToInt64(value);

これにより厄介なオーバーヘッドが追加されるため、これだけのことを行う場合は、おそらくそれを行うヘルパー メソッドを作成する必要があります。

public static long? getLongFromDB(object value)
{
    if (value == DBNull.Value) return null;
    return Convert.ToInt64(value);
}

次に、コードは次のようになります。

Int64 id_riga = getLongFromDB((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value)
    .GetValueOrDefault();
于 2012-12-27T17:38:09.323 に答える
4

問題のある行を次のように変更できます。

int id_macchina = ((sender as DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value as int?).GetValueOrDefault();

id_macchinaこれにより、データベースで列の値column_Machineがnullの場合、変数にデフォルト値のint(0)が与えられます( DBNullC#になります)

これを試して:

object aa = DBNull.Value;
int a = (aa as int?).GetValueOrDefault();

それが動作します!列が の場合、値は 0 になりますDBNull

* 編集 *

しかし、何か他のものを使用してみてください。これにより、データ型の変更など、いくつかのバグが隠される可能性があります。データベースで型が int ではなく long の場合、常に変数に 0 が割り当てられます。 @hvd to は、彼のコメントでそれを示します。

于 2012-12-27T17:36:58.960 に答える
1

私はあなたのコメントのいくつかに少し混乱しています。たとえば、コードのように、コメントは を含む行がToInt32エラーが発生した場所であることを示していますが、エラー メッセージは、エラーが 内からスローされたことを明確に示していますToInt64

また、データベースの値は null ではないとおっしゃいました。そうであれば、DBNull 値を取得できないため、コードを少し拡張して、ブレークポイントを配置し、セルを変換する前にセル内の値を直接検査できるようにすることをお勧めします。

以下に、役に立つと思われる変換ヘルパー関数を含む、使用できるサンプル コードをいくつか掲載しました。

//--------- inside the try block of your event handler -----------//
        var row = (sender as DataGridView).Rows[e.RowIndex];
        object objId = row.Cells["column_ID"].Value;
        object objMachine = row.Cells["column_Machine"].Value;
        // place a breakpoint on the line below, 
                    // so you can inspect the "obj..." values above to see
                    // if they are DBNull or not.

        var id_riga = objId.FromDb<Int64>();
        var id_macchina = objMachine.FromDb<Int32>();
//-----------continue your code here---------//

//----outside the form class, possibly in a separate file -----/
static class DbObjectExtensions {
    public static T FromDb<T>(this object dbObj, T defaultValueIfNull = default(T)) where T : IConvertible {
        if (Convert.IsDBNull(dbObj))
            return defaultValueIfNull;
        if (dbObj is T)
            return (T)dbObj;
        return (T)Convert.ChangeType(dbObj, typeof(T));
    }
}

また、上で見た「... null ではなく、DBNull です。この 2 つは異なります」というコメントをクリアしたいと思います。このステートメントは、C# では一般的に当てはまりますが、記述されたコンテキストでは実際には誤解を招きます。「[I] データベースで値をチェックしましたが、NULL ではありません」という以前のコメントに応えて書かれました。明確にするために、データベース フィールドの NULL は、ほとんどの .Net データベース プロバイダーで DBNull によって表されます。実際、データベースの NULL 値は通常、C# の DBNull と同じです。したがって、OP がデータベース値が NOT NULL であるという点で正しい場合、セル値は DBNull であってはならないということになります

もちろんnull、 と同じではないことは依然として真実であるDBNullため、オブジェクトが null であるかどうかを確認しても、それが DBNull であるかどうかは判断されません (ただし、それは OP が言ったことではありません)。

最後に、私が作成した拡張メソッド には、FromDB渡されたオブジェクトが DBNull の場合のデフォルトの戻り値のオプション パラメータが含まれています。これは次のように使用できます。

//assuming -1 isn't a valid 
var id_riga = objId.FromDb<Int64>(-1); id
if (id_riga == -1) { /*handle case for null db value*/ }

個人の好みによっては、上記のパラダイムは、他の回答で説明されている Nullable バージョンよりも理解しやすい場合があります。

于 2012-12-27T18:25:02.387 に答える