我使用SQLdatareader从数据库构建poco。除非在数据库中遇到空值,否则代码可以正常工作。例如,如果数据库中的FirstName列包含空值,则抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
在这种情况下处理空值的最佳方法是什么?
我使用SQLdatareader从数据库构建poco。除非在数据库中遇到空值,否则代码可以正常工作。例如,如果数据库中的FirstName列包含空值,则抛出异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
在这种情况下处理空值的最佳方法是什么?
当前回答
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();
}
其他回答
老问题了,但也许有人还需要一个答案
在现实生活中,我就是这样解决这个问题的
对于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?;
and
string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;
非常灵活,所以你可以插入任何查询读取任何列,它永远不会返回错误
在尝试读取它之前检查sqlreader.IsDBNull(indexFirstName)。
我尽了最大努力从DataTable中重新实现Field方法。https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field
如果您尝试转换DBNull,它将抛出。值转换为非空类型。否则它将转换为DBNull。值为null。
我还没有完全测试过。
public static T Field<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnIndex = sqlDataReader.GetOrdinal(columnName);
if (sqlDataReader.IsDBNull(columnIndex))
{
if (default(T) != null)
{
throw new InvalidCastException("Cannot convert DBNULL value to type " + typeof(T).Name);
}
else
{
return default(T);
}
}
else
{
return sqlDataReader.GetFieldValue<T>(columnIndex);
}
}
用法:
string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;
这里有很多有用的信息(和一些错误的信息)的答案,我想把它们放在一起。
这个问题的简短回答是检查DBNull -几乎每个人都同意这一点:)
与使用辅助方法读取每个SQL数据类型的可空值不同,泛型方法允许我们用更少的代码来解决这个问题。然而,对于可空值类型和引用类型,你不能有一个单一的泛型方法,这将在中详细讨论 可空类型作为泛型参数可能吗?和c#泛型类型约束为所有可空的。
所以,从@ZXX和@getpsyched的答案中,我们最终得到了这个,2个方法用于获取可空值,我已经添加了第三个非空值(它完成了基于方法命名的集合)。
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);
}
我通常使用列名,如果你使用列索引,可以修改这些。根据这些方法名,我可以判断我是否期望数据为空,这在查看很久以前编写的代码时非常有用。
提示;
数据库中没有可空列可以避免这个问题。如果你 对数据库有控制那么列应该非空由 默认值,只在必要时为空。 不要强制转换数据库值 使用c#的“as”操作符,因为如果强制转换错误,它就会 静默返回null。 使用默认值表达式将会改变 数据库空值到非空值的值类型,如int, datetime, 钻头等。
最后,在测试所有SQL Server数据类型的上述方法时,我发现你不能直接从SqlDataReader中获得一个char[],如果你想要一个char[],你必须获得一个字符串并使用ToCharArray()。
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]);