답변:
다음을 확인해야합니다 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
과 함께 ??
연산자를 연산자 와 결합하여 사용해야 합니다. 값 유형은 널 입력 가능으로 읽고 기본값이 제공되어야합니다.
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)는 0이 아니라 -1입니다. @Chris : 원하는 것을 사용하고 있는지 확인하십시오.
문자열의 경우 간단히 객체 버전 (배열 연산자를 사용하여 액세스)을 캐스트하고 널 (null) 문자열에 널 (null)을 입력하면됩니다.
employee.FirstName = (string)sqlreader[indexFirstName];
또는
employee.FirstName = sqlreader[indexFirstName] as string;
정수의 경우 nullable int로 캐스팅하면 GetValueOrDefault ()를 사용할 수 있습니다
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
또는 null 병합 연산자 (??
).
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
null
DBNull 객체 가 아닙니다 . 두 문의 차이점은 첫 번째 문자열이 문자열이 아닌 경우 실패하지만 두 번째 문은 문자열이 아닌 경우 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 Reader와 함께 작동합니다.
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을 빈 문자열로 바꿉니다. 이 경우 코드에 오류가 발생하지 않습니다.
널 (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"]);
}
헬퍼 메소드 작성 방법
문자열
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 's answer에 영향을 주어 열 값을 이름으로 확인하는 일반적인 방법을 만들었습니다.
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")
유용한 정보 (및 잘못된 정보)가 널리 퍼져있는 많은 답변이 있습니다. 모두 통합하고 싶습니다.
질문에 대한 짧은 대답은 DBNull을 확인하는 것입니다. 거의 모든 사람들 이이 비트에 동의합니다 :)
헬퍼 메소드를 사용하여 SQL 데이터 유형 당 널 입력 가능 값을 읽는 대신 일반 메소드를 사용하면 훨씬 적은 코드로이를 해결할 수 있습니다. 그러나 nullable 값 형식과 참조 형식 모두에 대해 단일 제네릭 메서드를 사용할 수 없습니다. 가능한 일반적인 매개 변수로 Nullable 형식으로 길게 설명 합니까? 그리고 모든 NULLABLE가 C #을 제네릭 형식 제약 조건 .
따라서 @ZXX 및 @getpsyched의 답변에 이어 nullable 값을 얻는 두 가지 방법과 null이 아닌 값에 대한 세 번째 방법을 추가했습니다 (메서드 명명을 기반으로 설정을 완료 함).
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);
}
나는 일반적으로 열 이름을 사용하고 열 인덱스를 사용하는 경우 이름을 변경하십시오. 이러한 메서드 이름을 기반으로 데이터가 nullable이 될지 여부를 알 수 있으며 오래 전에 작성된 코드를 볼 때 매우 유용합니다.
팁;
마지막으로, 모든 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);
}
}
핸들 DbNull을 현명하게 변환합니다.
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
int colIndex = reader.GetOrdinal(fieldname);
@ marc_s의SafeGetString
함수를 쉽게 오버로드하십시오 .