回答:
次の点を確認する必要があります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のチェックなど、キャストを処理します。
sqlreader[indexAge] as string ?? ""
した場合は、常にが取得され""
ます。本当に必要かどうかを検討して(int?)sqlreader[indexAge] ?? defaultValue
ください。SQLが変更されると、不正な値ではなく例外が発生します。@ Stevo3000:default(int)は-1ではなく0です。@Chris:本当に必要なものを使用していることを確認してください。
文字列の場合は、オブジェクトのバージョン(配列演算子を使用してアクセス)をキャストし、nullの場合はnull文字列で終了できます。
employee.FirstName = (string)sqlreader[indexFirstName];
または
employee.FirstName = sqlreader[indexFirstName] as string;
整数の場合、null許容intにキャストすると、GetValueOrDefault()を使用できます
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
またはnull結合演算子(??
)。
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
null
DBNullオブジェクトではなく、DBNullオブジェクトです。2つのステートメントの違いは、最初のステートメントが文字列でない場合は失敗し、2番目のステートメントは文字列でない場合はnullを返すだけです。
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();
このソリューションはベンダー依存性が低く、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);
}
SELECTステートメントのnull値を適切なものに置き換える傾向があります。
SELECT ISNULL(firstname, '') FROM people
ここでは、すべてのnullを空の文字列に置き換えます。その場合、コードはエラーになりません。
ジェネリック関数を記述してヌルをチェックし、ヌルの場合はデフォルト値を含めることができます。Datareaderを読み取るときにこれを呼び出します
public T CheckNull<T>(object obj)
{
return (obj == DBNull.Value ? default(T) : (T)obj);
}
データリーダーを読むとき
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"]);
}
ヘルパーメソッドの作成方法
文字列の場合
private static string MyStringConverter(object o)
{
if (o == DBNull.Value || o == null)
return "";
return o.ToString();
}
使用法
MyStringConverter(read["indexStringValue"])
Int
private static int MyIntonverter(object o)
{
if (o == DBNull.Value || o == null)
return 0;
return Convert.ToInt32(o);
}
使用法
MyIntonverter(read["indexIntValue"])
日付
private static DateTime? MyDateConverter(object o)
{
return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
}
使用法
MyDateConverter(read["indexDateValue"])
注:DateTimeの場合、varialbeを次のように宣言します。
DateTime? variable;
marc_sによる回答への追加として、より一般的な拡張メソッドを使用して、SqlDataReaderから値を取得できます。
public static T SafeGet<T>(this SqlDataReader reader, int col)
{
return reader.IsDBNull(col) ? default(T) : reader.GetFieldValue<T>(col);
}
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")
条件演算子を使用できます。
employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";
ここにはたくさんの答えがあり、有用な情報(およびいくつかの間違った情報)が広がっています。それらをすべてまとめたいと思います。
質問への短い答えは、DBNullをチェックすることです-ほとんど誰もがこのビットに同意します:)
ヘルパーメソッドを使用してSQLデータ型ごとにnull許容値を読み取る代わりに、ジェネリックメソッドを使用すると、はるかに少ないコードでこれに対処できます。ただし、null許容値の型と参照型の両方に単一のジェネリックメソッドを使用することはできません。これについては、null許容型で汎用パラメーターとして詳しく説明してい ますか?そしてnull可能すべてのための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()を使用する必要があります。
このメソッドは、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"];
}
古い質問ですが、おそらく誰かが答えを必要としています
実際に私はこの問題をそのように回避しました
intの場合:
public static object GatDataInt(string Query, string Column)
{
SqlConnection DBConn = new SqlConnection(ConnectionString);
if (DBConn.State == ConnectionState.Closed)
DBConn.Open();
SqlCommand CMD = new SqlCommand(Query, DBConn);
SqlDataReader RDR = CMD.ExecuteReader();
if (RDR.Read())
{
var Result = RDR[Column];
RDR.Close();
DBConn.Close();
return Result;
}
return 0;
}
""は空の文字列であるため、文字列の場合も0ではなく ""を返します。
だからあなたはそれを好きに使うことができます
int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?;
そして
string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;
非常に柔軟なので、任意のクエリを挿入して任意の列を読み取ることができ、エラーで戻ることはありません
@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);
}
}
ConvertはDbNullを適切に処理します。
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
int colIndex = reader.GetOrdinal(fieldname);
@ marc_sのSafeGetString
関数を簡単にオーバーロードします。