SQL 数据读取器 - 处理空列值
我正在使用 SQLdatareader 从数据库构建 POCO。除非在数据库中遇到空值,否则该代码将正常工作。例如,如果数据库中的 FirstName 列包含空值,则会引发异常。
employee.FirstName = sqlreader.GetString(indexFirstName);
在这种情况下我该如何处理空值?
I'm using a SQLdatareader to build POCOs from a database. The code works except when it encounters a null value in the database. For example, if the FirstName column in the database contains a null value, an exception is thrown.
employee.FirstName = sqlreader.GetString(indexFirstName);
How can I handle null values in this situation?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
您需要检查
IsDBNull
:这是检测和处理这种情况的唯一可靠方法。
我将这些东西包装到扩展方法中,并且如果列确实为 null ,则倾向于返回默认值:
现在您可以这样调用它:
并且您永远不必担心异常或 <再次使用 code>null 值。
You need to check for
IsDBNull
:That's your only reliable way to detect and handle this situation.
I wrapped those things into extension methods and tend to return a default value if the column is indeed
null
:Now you can call it like this:
and you'll never have to worry about an exception or a
null
value again.您应该将
as
运算符与??
运算符结合使用作为默认值。值类型需要被读取为可为空并给出默认值。as
运算符处理转换,包括检查 DBNull。You should use the
as
operator combined with the??
operator for default values. Value types will need to be read as nullable and given a default.The
as
operator handles the casting including the check for DBNull.对于整数,如果转换为可为 null 的 int,则可以使用 GetValueOrDefault()
或 null 合并运算符 (
??
)。For integers, if you cast to a nullable int, you can use GetValueOrDefault()
or the null-coalescing operator (
??
).IsDbNull(int)
通常比使用GetSqlDateTime
等方法然后与DBNull.Value
进行比较要慢得多。尝试SqlDataReader
的这些扩展方法。像这样使用它们:
IsDbNull(int)
is usually much slower than using methods likeGetSqlDateTime
and then comparing toDBNull.Value
. Try these extension methods forSqlDataReader
.Use them like this:
if(reader.IsDBNull(ColumnIndex)) {//logic}
正如许多答案所述。我想提一下,如果您使用列名,则仅比较类型可能会更舒服。
if(reader.IsDBNull(ColumnIndex)) {// logic}
works as many answers says.And I want to mention if you working with column names, just comparing types may be more comfortable.
当使用列名在数据读取器中返回行时,我认为不存在 NULL 列值。
如果你这样做
datareader["columnName"].ToString();
它总是会给你一个可以是空字符串的值(String.Empty
如果你需要比较)。我会使用以下内容并且不会太担心:
I don't think there's a NULL column value, when rows are returned within a datareader using the column name.
If you do
datareader["columnName"].ToString();
it will always give you a value that can be a empty string (String.Empty
if you need to compare).I would use the following and wouldn't worry too much:
您可以编写一个通用函数来检查 Null 并在它为 NULL 时包含默认值。读取Datareader时调用此方法
读取Datareader时使用
You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader
When reading the Datareader use
一种方法是检查数据库空值:
One way to do it is to check for db nulls:
该解决方案对供应商的依赖性较小,并且可与 SQL、OleDB 和 MySQL Reader 配合使用:
This Solution is less vendor-dependent and works with an SQL, OleDB, and MySQL Reader:
通过 getpsyched 的答案的影响,我创建了一个通用方法,通过名称检查列值
用法:
By influencing from getpsyched's answer, I created a generic method which checks column value by its name
Usage:
我倾向于做的是将 SELECT 语句中的空值替换为适当的值。
在这里,我将每个 null 替换为空白字符串。在这种情况下,您的代码不会抛出错误。
What I tend to do is replace the null values in the SELECT statement with something appropriate.
Here I replace every null with a blank string. Your code won't throw in error in that case.
在尝试读取之前请检查
sqlreader.IsDBNull(indexFirstName)
。Check
sqlreader.IsDBNull(indexFirstName)
before you try to read it.作为 marc_s 答案的补充,您可以使用更通用的扩展方法从 SqlDataReader 获取值:
As an addition to the answer by marc_s, you can use a more generic extension method to get values from the SqlDataReader:
我想你会想使用:
I think you would want to use:
如何创建辅助方法
对于字符串
用法
对于 Int
用法
对于日期
用法
注意:对于 DateTime,将变量声明为
how to about creating helper methods
For String
Usage
For Int
Usage
For Date
Usage
Note: for DateTime declare varialbe as
这些都不是我想要的:
None of these was quite what i wanted:
这里有很多答案,其中传播着有用的信息(以及一些错误的信息),我想将它们放在一起。
这个问题的简短答案是检查 DBNull - 几乎每个人都同意这一点:)
通用方法允许我们用更少的代码来解决这个问题,而不是使用辅助方法来读取每个 SQL 数据类型的可为空值。但是,您不能为可为空值类型和引用类型提供单一泛型方法,这将在
可以为空类型作为泛型参数吗? 和 < a href="https://stackoverflow.com/questions/19831157/c-sharp-generic-type-constraint-for-everything-nullable">针对所有可为 null 的内容的 C# 泛型类型约束。
因此,根据 @ZXX 和 @getpsyched 的答案,我们最终得到了两种获取可为空值的方法,并且我添加了第三种用于非空值的方法(它根据方法命名完成了集合)。
我通常使用列名称,如果您使用列索引,请更改这些名称。根据这些方法名称,我可以判断数据是否可以为空,这在查看很久以前编写的代码时非常有用。
尖端;
可以控制数据库,那么列应该是非空的
默认且仅在必要时可为空。
使用 C# 'as' 运算符,因为如果转换错误,它将
默默返回null。
数据库将 null 值转换为 int、datetime 等值类型的非空值
最后,在对所有 SQL Server 数据类型测试上述方法时,
我发现您无法直接从 SqlDataReader 获取 char[],如果您想要 char[],则必须获取字符串并使用 ToCharArray( )。
There are a lot of answers here with useful info (and some wrong info) spread about, I'd like to bring it all together.
The short answer to the question is to check for DBNull - almost everyone agrees on this bit :)
Rather than using a helper method to read nullable values per SQL data type a generic method allows us to address this with a lot less code. However, you can't have a single generic method for both nullable value types and reference types, this is discussed at length in
Nullable type as a generic parameter possible? and C# generic type constraint for everything nullable.
So, following on from the answers from @ZXX and @getpsyched we end up with this, 2 methods for getting nullable values and I've added a 3rd for non-null values (it completes the set based on method naming).
I usually use column names, alter these if you use column indexes. Based on these method names I can tell whether I'm expecting the data to be nullable or not, quite useful when looking at code written a long time ago.
Tips;
have control over the database then columns should be non-null by
default and only nullable where necessary.
with the C# 'as' operator because if the cast is wrong it will
silently return null.
database nulls to non-null values for value types like int, datetime,
bit etc.
Lastly, whilst testing the above methods across all SQL Server data types I discovered you can't directly get a char[] from a SqlDataReader, if you want a char[] you will have to get a string and use ToCharArray().
我们使用一系列静态方法从数据读取器中提取所有值。因此,在这种情况下,我们将调用 DBUtils.GetString(sqlreader(indexFirstName)) 创建静态/共享方法的好处是,您不必一遍又一遍地执行相同的检查...
静态方法将包含检查空值的代码(请参阅本页上的其他答案)。
We use a series of static methods to pull all of the values out of our data readers. So in this case we'd be calling
DBUtils.GetString(sqlreader(indexFirstName))
The benefit of creating static/shared methods is that you don't have to do the same checks over and over and over...The static method(s) would contain code to check for nulls (see other answers on this page).
您可以使用条件运算符:
You may use the conditional operator:
这是辅助类,其他人可以根据 @marc_s 的回答使用它们:
Here is helper class which others can use if they need based on @marc_s answer:
在 c# 7.0 中我们可以这样做:
所以如果是的话它将保留 null 值。
in c# 7.0 we can do :
so it will keep null value if it is.
我尽力从
DataTable
重新实现Field
方法。 https://learn.microsoft.com/en- us/dotnet/api/system.data.datarowextensions.field如果您尝试将
DBNull.Value
转换为不可空类型,则会抛出异常。否则,它将把DBNull.Value
转换为null
。我还没有完全测试过。
用法:
I did my best to reimplement the
Field
method fromDataTable
. https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.fieldIt will throw if you try to convert a
DBNull.Value
to a non-nullable type. Otherwise it will convertDBNull.Value
tonull
.I haven't fully tested it.
Usage:
我使用下面列出的代码来处理读入数据表的 Excel 工作表中的空单元格。
I am using the code listed below to handle null cells in an Excel sheet that is read in to a datatable.
和/或使用三元运算符进行赋值:
根据每个属性类型替换默认值(当为空时)...
and / or use ternary operator with assignment:
replace the default (when null) value as appropriate for each property type...
此方法依赖于indexFirstName,它应该是从零开始的列序数。
如果您不知道列索引但不想检查名称,您可以使用此扩展方法:
并使用如下方法:
This method is dependent on indexFirstName which should be the zero-based column ordinal.
If you don't know the column index but wan't to check a name you can use this extension method instead:
And use the method like this:
老问题,但也许有人仍然需要真正的答案,
我像这样解决了这个问题
对于 int :
对于字符串相同,只需返回“”而不是 0,因为“”是空字符串,
所以你可以像使用它一样
并且
非常灵活,所以你可以插入任何查询来读取任何列,它永远不会返回错误
Old question but maybe someone still need an answer
in real i worked around this issue like that
For int :
the same for string just return "" instead of 0 as "" is empty string
so you can use it like
and
very flexible so you can insert any query to read any column and it'll never return with error
整齐的一行:
neat one-liner:
合理地转换句柄 DbNull。
Convert handles DbNull sensibly.
你也可以检查一下
you can ever check for this as well