340

SQLdatareader を使用して、データベースから POCO を構築しています。コードは、データベースで null 値が検出された場合を除いて機能します。たとえば、データベースの FirstName 列に null 値が含まれている場合、例外がスローされます。

employee.FirstName = sqlreader.GetString(indexFirstName);

この状況で null 値を処理する最善の方法は何ですか?

4

30 に答える 30

539

以下を確認する必要がありますIsDBNull

if(!SqlReader.IsDBNull(indexFirstName))
{
  employee.FirstName = sqlreader.GetString(indexFirstName);
}

これが、この状況を検出して処理するための唯一の信頼できる方法です。

私はこれらのものを拡張メソッドにラップし、列が実際にある場合はデフォルト値を返す傾向がありますnull:

public static string SafeGetString(this SqlDataReader reader, int colIndex)
{
   if(!reader.IsDBNull(colIndex))
       return reader.GetString(colIndex);
   return string.Empty;
}

これで、次のように呼び出すことができます。

employee.FirstName = SqlReader.SafeGetString(indexFirstName);

null例外や値について心配する必要はもうありません。

于 2009-11-20T17:25:52.843 に答える
237

デフォルト値asの演算子と組み合わせて演算子を使用する必要があります。??値の型は、null 許容として読み取り、デフォルトを指定する必要があります。

employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);

asオペレーターは、DBNull のチェックを含むキャストを処理します。

于 2010-07-22T11:54:22.023 に答える
27

IsDbNull(int)GetSqlDateTime通常、 のようなメソッドを使用してから と比較するよりもはるかに遅くなりますDBNull.Value。のこれらの拡張メソッドを試してくださいSqlDataReader

public static T Def<T>(this SqlDataReader r, int ord)
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return default(T);
    return ((INullable)t).IsNull ? default(T) : (T)t;
}

public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? (T?)null : (T)t;
}

public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
    var t = r.GetSqlValue(ord);
    if (t == DBNull.Value) return null;
    return ((INullable)t).IsNull ? null : (T)t;
}

次のように使用します。

var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
于 2010-07-22T11:44:49.140 に答える
14

列名を使用してデータリーダー内で行が返される場合、 NULL列値はないと思います。

そうすればdatareader["columnName"].ToString();、空の文字列になる可能性のある値が常に得られます(String.Empty比較する必要がある場合)。

私は以下を使用しますが、あまり心配しません。

employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
于 2012-03-06T17:15:22.773 に答える
13

これを行う 1 つの方法は、db null をチェックすることです。

employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
    ? ""
    : sqlreader.GetString(indexFirstName));
于 2009-11-20T17:27:00.080 に答える
12

このソリューションは、ベンダーへの依存度が低く、SQL、OleDB、および MySQL リーダーで動作します。

public static string GetStringSafe(this IDataReader reader, int colIndex)
{
    return GetStringSafe(reader, colIndex, string.Empty);
}

public static string GetStringSafe(this IDataReader reader, int colIndex, string defaultValue)
{
    if (!reader.IsDBNull(colIndex))
        return reader.GetString(colIndex);
    else
        return defaultValue;
}

public static string GetStringSafe(this IDataReader reader, string indexName)
{
    return GetStringSafe(reader, reader.GetOrdinal(indexName));
}

public static string GetStringSafe(this IDataReader reader, string indexName, string defaultValue)
{
    return GetStringSafe(reader, reader.GetOrdinal(indexName), defaultValue);
}
于 2012-10-16T08:18:34.237 に答える
10

Nullをチェックし、NULLの場合はデフォルト値を含める汎用関数を作成できます。Datareader を読み取るときにこれを呼び出します

public T CheckNull<T>(object obj)
        {
            return (obj == DBNull.Value ? default(T) : (T)obj);
        }

Datareader を使用して読み取る場合

                        while (dr.Read())
                        {
                            tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon();
                            Bpn.BPN_Date = CheckNull<DateTime?>(dr["BPN_Date"]);
                            Bpn.Cust_Backorder_Qty = CheckNull<int?>(dr["Cust_Backorder_Qty"]);
                            Bpn.Cust_Min = CheckNull<int?>(dr["Cust_Min"]);
                         }
于 2016-09-20T00:13:34.970 に答える
8

私がよく行うのは、SELECT ステートメントの null 値を適切なものに置き換えることです。

SELECT ISNULL(firstname, '') FROM people

ここでは、すべての null を空白の文字列に置き換えます。その場合、コードはエラーをスローしません。

于 2009-11-20T17:28:00.813 に答える
7

getpsyched の回答から影響を受けて、名前で列の値をチェックする汎用メソッドを作成しました

public static T SafeGet<T>(this System.Data.SqlClient.SqlDataReader reader, string nameOfColumn)
{
  var indexOfColumn = reader.GetOrdinal(nameOfColumn);
  return reader.IsDBNull(indexOfColumn) ? default(T) : reader.GetFieldValue<T>(indexOfColumn);
}

使用法:

var myVariable = SafeGet<string>(reader, "NameOfColumn")
于 2018-12-24T11:57:45.730 に答える
6

sqlreader.IsDBNull(indexFirstName)読もうとする前に確認してください。

于 2009-11-20T17:28:26.580 に答える
4

これらのどれも私が望んでいたものではありませんでした:

 public static T GetFieldValueOrDefault<T>(this SqlDataReader reader, string name)
 {
     int index = reader.GetOrdinal(name);
     T value = reader.IsDBNull(index) ? default(T) : reader.GetFieldValue<T>(index);
     return value;
 }
于 2021-01-29T17:58:23.380 に答える
3

私はあなたが使いたいと思うと思います:

SqlReader.IsDBNull(indexFirstName)
于 2009-11-20T17:31:50.330 に答える
2

一連の静的メソッドを使用して、データ リーダーからすべての値を引き出します。DBUtils.GetString(sqlreader(indexFirstName)) 静的/共有メソッドを作成する利点は、同じチェックを何度も何度も行う必要がないことです...

静的メソッドには、null をチェックするコードが含まれます (このページの他の回答を参照してください)。

于 2009-11-20T17:27:39.237 に答える
2

ここには、有用な情報 (およびいくつかの間違った情報) が広まっている多くの回答があります。すべてをまとめたいと思います。

質問に対する簡単な答えは、DBNull をチェックすることです - ほとんどの人がこのビットに同意します :)

ヘルパー メソッドを使用して SQL データ型ごとに null 許容値を読み取るのではなく、ジェネリック メソッドを使用すると、はるかに少ないコードでこれに対処できます。ただし、null 許容値型と参照型の両方に対して単一のジェネリック メソッドを使用することはできません すべての nullable に対する C# ジェネリック型の制約。

したがって、@ZXX および @getpsyched からの回答に続いて、null 許容値を取得するための 2 つのメソッドと、null 以外の値用の 3 つ目のメソッドを追加しました (メソッドの命名に基づいてセットを完成させます)。

public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
{
    int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
    return sqlDataReader.GetFieldValue<T>(columnOrdinal);
}

通常は列名を使用しますが、列インデックスを使用する場合はこれらを変更してください。これらのメソッド名に基づいて、データが null 可能であると想定しているかどうかを判断できます。これは、かなり前に作成されたコードを調べるときに非常に役立ちます。

チップ;

  • データベースに NULL 可能な列を持たないことで、この問題を回避できます。データベースを制御できる場合、列はデフォルトで非 null であり、必要な場合にのみ null 可能にする必要があります。
  • C# の 'as' 演算子を使用してデータベースの値をキャストしないでください。キャストが間違っていると、暗黙のうちに null が返されます。
  • デフォルト値式を使用すると、データベースの null が、int、datetime、bit などの値型の非 null 値に変更されます。

最後に、上記のメソッドをすべての SQL Server データ型でテストしたところ、SqlDataReader から char[] を直接取得できないことがわかりました。char[] が必要な場合は、文字列を取得して ToCharArray() を使用する必要があります。

于 2019-06-04T16:06:41.877 に答える
1

以下にリストされているコードを使用して、データテーブルに読み込まれるExcelシートのヌルセルを処理しています。

if (!reader.IsDBNull(2))
{
   row["Oracle"] = (string)reader[2];
}
于 2012-11-02T13:43:28.083 に答える
1
private static void Render(IList<ListData> list, IDataReader reader)
        {
            while (reader.Read())
            {

                listData.DownUrl = (reader.GetSchemaTable().Columns["DownUrl"] != null) ? Convert.ToString(reader["DownUrl"]) : null;
                //没有这一列时,让其等于null
                list.Add(listData);
            }
            reader.Close();
        }
于 2013-05-31T06:25:11.510 に答える
1

このメソッドは、0 から始まる列の序数である indexFirstName に依存しています。

if(!sqlReader.IsDBNull(indexFirstName))
{
  employee.FirstName = sqlreader.GetString(indexFirstName);
}

列のインデックスがわからないが名前を確認したくない場合は、代わりにこの拡張メソッドを使用できます。

public static class DataRecordExtensions
{
    public static bool HasColumn(this IDataRecord dr, string columnName)
    {
        for (int i=0; i < dr.FieldCount; i++)
        {
            if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
                return true;
        }
        return false;
    }
}

そして、次のような方法を使用します。

if(sqlReader.HasColumn("FirstName"))
{
  employee.FirstName = sqlreader["FirstName"];
}
于 2016-02-12T12:47:28.617 に答える
1

および/または代入で三項演算子を使用します:

employee.FirstName = rdr.IsDBNull(indexFirstName))? 
                     String.Empty: rdr.GetString(indexFirstName);

各プロパティ タイプに応じて、デフォルト (null の場合) 値を置き換えます...

于 2009-11-20T17:28:25.477 に答える
1

@marc_sの回答に基づいて、必要に応じて他の人が使用できるヘルパークラスを次に示します。

public static class SQLDataReaderExtensions
    {
        public static int SafeGetInt(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? 0 : dataReader.GetInt32(fieldIndex);
        }

        public static int? SafeGetNullableInt(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.GetValue(fieldIndex) as int?;
        }

        public static string SafeGetString(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? string.Empty : dataReader.GetString(fieldIndex);
        }

        public static DateTime? SafeGetNullableDateTime(this SqlDataReader dataReader, string fieldName)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.GetValue(fieldIndex) as DateTime?;
        }

        public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName)
        {
            return SafeGetBoolean(dataReader, fieldName, false);
        }

        public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName, bool defaultValue)
        {
            int fieldIndex = dataReader.GetOrdinal(fieldName);
            return dataReader.IsDBNull(fieldIndex) ? defaultValue : dataReader.GetBoolean(fieldIndex);
        }
    }
于 2019-02-12T19:28:34.007 に答える
-3

あなたもこれをチェックすることができます

if(null !=x && x.HasRows)
{ ....}
于 2011-04-20T08:57:49.930 に答える