SQLdatareader を使用して、データベースから POCO を構築しています。コードは、データベースで null 値が検出された場合を除いて機能します。たとえば、データベースの FirstName 列に null 値が含まれている場合、例外がスローされます。
employee.FirstName = sqlreader.GetString(indexFirstName);
この状況で null 値を処理する最善の方法は何ですか?
SQLdatareader を使用して、データベースから POCO を構築しています。コードは、データベースで null 値が検出された場合を除いて機能します。たとえば、データベースの FirstName 列に null 値が含まれている場合、例外がスローされます。
employee.FirstName = sqlreader.GetString(indexFirstName);
この状況で null 値を処理する最善の方法は何ですか?
以下を確認する必要があります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
例外や値について心配する必要はもうありません。
デフォルト値as
の演算子と組み合わせて演算子を使用する必要があります。??
値の型は、null 許容として読み取り、デフォルトを指定する必要があります。
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
as
オペレーターは、DBNull のチェックを含むキャストを処理します。
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]);
列名を使用してデータリーダー内で行が返される場合、 NULL列値はないと思います。
そうすればdatareader["columnName"].ToString();
、空の文字列になる可能性のある値が常に得られます(String.Empty
比較する必要がある場合)。
私は以下を使用しますが、あまり心配しません。
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
これを行う 1 つの方法は、db null をチェックすることです。
employee.FirstName = (sqlreader.IsDBNull(indexFirstName)
? ""
: sqlreader.GetString(indexFirstName));
このソリューションは、ベンダーへの依存度が低く、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);
}
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"]);
}
私がよく行うのは、SELECT ステートメントの null 値を適切なものに置き換えることです。
SELECT ISNULL(firstname, '') FROM people
ここでは、すべての null を空白の文字列に置き換えます。その場合、コードはエラーをスローしません。
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")
sqlreader.IsDBNull(indexFirstName)
読もうとする前に確認してください。
これらのどれも私が望んでいたものではありませんでした:
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;
}
私はあなたが使いたいと思うと思います:
SqlReader.IsDBNull(indexFirstName)
一連の静的メソッドを使用して、データ リーダーからすべての値を引き出します。DBUtils.GetString(sqlreader(indexFirstName))
静的/共有メソッドを作成する利点は、同じチェックを何度も何度も行う必要がないことです...
静的メソッドには、null をチェックするコードが含まれます (このページの他の回答を参照してください)。
ここには、有用な情報 (およびいくつかの間違った情報) が広まっている多くの回答があります。すべてをまとめたいと思います。
質問に対する簡単な答えは、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 可能であると想定しているかどうかを判断できます。これは、かなり前に作成されたコードを調べるときに非常に役立ちます。
チップ;
最後に、上記のメソッドをすべての SQL Server データ型でテストしたところ、SqlDataReader から char[] を直接取得できないことがわかりました。char[] が必要な場合は、文字列を取得して ToCharArray() を使用する必要があります。
以下にリストされているコードを使用して、データテーブルに読み込まれるExcelシートのヌルセルを処理しています。
if (!reader.IsDBNull(2))
{
row["Oracle"] = (string)reader[2];
}
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();
}
このメソッドは、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"];
}
および/または代入で三項演算子を使用します:
employee.FirstName = rdr.IsDBNull(indexFirstName))?
String.Empty: rdr.GetString(indexFirstName);
各プロパティ タイプに応じて、デフォルト (null の場合) 値を置き換えます...
@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);
}
}
あなたもこれをチェックすることができます
if(null !=x && x.HasRows)
{ ....}