1 问题重现

(1)新建项目DBNullExp。项目属性为“控制台应用程序”;

(2)在项目下新建数据集Schools(数据集文件的后缀名为.xsd);

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWwyaXNvZnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

(3)在数据集下新建数据表Students,表字段的定义例如以下表所看到的:

字段名

说明

ID

dc.DataType = Type.GetType("System.Int32");//类型

dc.AutoIncrement = true;//自己主动增量

dc.AutoIncrementSeed = 1;//起始为1

dc.AutoIncrementStep = 1;//步长为1

dc.AllowDBNull = false;//非空

Name

dc.DataType = Type.GetType("System.String");//类型

dc.AllowDBNull = false;//非空

Age

dc.DataType = Type.GetType("System.Int32");//类型

dc.AllowDBNull = true;//可空

Email

dc.DataType = Type.GetType("System.String");//类型

dc.AllowDBNull = true;//可空

(4)向Students数据表插入5条演示样例数据。

Schools.StudentsDataTable sdt = new Schools.StudentsDataTable();
sdt.Rows.Add(new object[] { null, "张三", 25, "zhangsan@sina.com" });
sdt.Rows.Add(new object[] { null, "李四", 23, "lisi@sina.com" });
sdt.Rows.Add(new object[] { null, "王五", 24, "wangwu@sina.com" });
sdt.Rows.Add(new object[] { null, "周六", null, null });
sdt.Rows.Add(new object[] { null, "吴七", 25, "wuqi@sina.com" });

(5)查询数据表sdt,获取当中年龄大于24的学生信息输出到界面。

var newStudentList = sdt.Where(it => it.Age > 25).ToList();
foreach (var s in newStudentList)
{
Console.WriteLine(s.Name);
}

(6)执行代码,抛出例如以下图所看到的异常。

2 问题分析与解决

从异常提示信息能够看出,问题出在Students表的Age字段上,异常信息中指出Age字段的值为DBNull,那么什么是DBNull。它与我们常常见到的Null又有什么差别?

Null指的是无效的对象引用。而DBNull是一个类。DBNull.Value是它唯一的实例。DBNull的实例DBNull.Value是数据库表中的空数据在.Net代码中的表现形式。我们知道,当数据库表中的可空字段没有被赋值时,数据库表中的该字段会被指定为Null,那么这个Null值在.Net代码中该怎样表示呢,使用的就是DBNull.Value。反过来说。在代码中。当一个字段的值等于DBNull.Value,那就说明这个字段在数据库中保存的值为Null。也就是说它在数据库中的值为空。所以,DBNull.Value对象指向有效的对象。并不像Null没有指向不论什么有效的对象。

再来看看我们实例中Students表的数据。例如以下图所看到的。

从图中能够看出。名为“周六”的学生的Age字段的值为空,确实存在异常信息所说的Age值为DBNull的情形。

那么,为什么,Age字段的值为DBNull就会抛出异常呢?我不就是想获取一下学生的Age值吗,没有值返回给我一个DBNull.Value不就得了吗。为什么会抛出异常呢?

继续深挖异常源头。通过查看异常的InnerException信息,得知该异常的内部异常为“指定的转换无效”,并定位到异常产生的问题代码。

[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Design.TypedDataSetGenerator", "4.0.0.0")]
public int Age {
get {
try {
return ((int)(this[this.tableStudents.AgeColumn]));
}
catch (global::System.InvalidCastException e) {
throw new global::System.Data.StrongTypingException("表“Students”中列“Age”的值为DBNull。 ", e);
}
}
set {
this[this.tableStudents.AgeColumn] = value;
}
}

问题代码为:

return ((int)(this[this.tableStudents.AgeColumn]));

查看问题代码中this[this.tableStudents.AgeColumn]的值。为DBNull.Value。再将这个DBNull.Value隐式转换成整型数据时产生了异常。由于两者之间根本无法进行类型转换。这段代码是在新建数据集及创建表时自己主动生成的。所以改动需谨慎。

可是不知道当时微软为什么不在这里加上一个特殊处理,要是返回值为DBNull.Value。就直接返回0。为什么不这样做。就不去瞎推測了。

找到解决方法要紧。

3 解决方法

我们除了使用“it.Age”的方式来获取字段的值外,还能够使用“it["Age"]”的方式来获取表中的字段值。且知道当数据库字段值为空时,“it["Age"]”获取到的值会是DBNull.Value且不会抛出异常。所以我们就能够使用“it["Age"]”方式得到Age的值再与DBNull.Value比較。当不相等时再进行类型转换操作。这样一切就OK啦。改动后的代码例如以下所看到的。

var newStudentList1 = sdt.Where(it => it["Age"] != DBNull.Value && (int)it["Age"] > 24).ToList();

再次运行程序,得到以下想要的结果。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWwyaXNvZnQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

因DataTable的字段值为DBNull引发的异常的更多相关文章

  1. C#三种判断数据库中取出的字段值是否为空(NULL) 的方法

    操作数据库,需要判断返回的字段值是否为空,收集了3种方法供参考 1 通过System.DBNull判断,网上大部分都使用这个方法. DataTable dt;                     ...

  2. 程序处理数据库中值字段值为null的查询显示

    1.如果你做了一个简单的注册界面,需要用户进行注册,但有些项是不必要填的,当用户完成注册时,数据库表中的相应字段的值会写入null,但如何将查询的字段的值null显示出来? 2.首先我们学习一下如何向 ...

  3. 使用泛型集合取代datatable作为返回值实现面向对象

    开会的时候,师父说.我们在机房重构时,尽量不要用datatable作为返回值.改用泛型集合的方式,这样能够实现真正的面向对象. 通过查资料和同学交流,把这个问题给攻克了. 对于泛型集合.我也有了一些认 ...

  4. datagridcolumn单元格怎么显示查询到的某个表的字段值(字段值可能为多个)

    例如,在之前做的项目中,查询mhz_xckcr表,select出某个业务的现场勘察人信息,select出的现场勘察人姓名(可能有多个)要在前台datagrid的一个datagridcolmn单元格显示 ...

  5. Mysql按照字段值做分组行转列查询

    今天做个后台服务,有个需求是批量生成一批表的数据,如果用BulkInsert会提升很大一截提交效率,但是如果用循环构造提交的Datable,则算法开销太高,所以用这种查询批量查出符合格式的DataTa ...

  6. 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效

    数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...

  7. SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段值)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 方法一:使用拼接SQL,静态列字段: 方法二:使用拼接SQL, ...

  8. MSCRM CRM 获取PickList 字段值函数解决方案

    表单中有很多picklist字段 不想写链接stringmap代码: 实体ID查询方法: SELECT ObjectTypeCode from Entity  where  name='实体名称' 调 ...

  9. Mysql Sql语句令某字段值等于原值加上一个字符串

    MySQL连贯字符串不能利用加号(+),而利用concat. 比方在aa表的name字段前加字符'x',利用: update aa set name=concat('x',name); 替换: UPD ...

随机推荐

  1. [ARC100]E:Or Plus Max(FZT)

    https://arc100.contest.atcoder.jp/tasks/arc100_c 一个很自然的想法是,对于每个K求出i or j=k的所有a[i]+a[j]的最大值ans[k],答案就 ...

  2. 【枚举】Codeforces Round #394 (Div. 2) C. Dasha and Password

    纪念死去的智商(虽然本来就没有吧……) 三重循环枚举将哪三个fix string作为数字.字母和符号位.记下最小的值就行了. 预处理之后这个做法应该是O(n^3)的,当然完全足够.不预处理是O(n^3 ...

  3. python基础-协程函数、递归、模块、包等内容

    1. 协程函数 1.1 yield基本用法 yield作用 1.把函数的执行结果封装好,即封装__iter__和__next__,即得到一个迭代器 2.与return功能类似,都可以返回值,但不同的是 ...

  4. C#SerialPort实现串口控制继电器

    最近做了一个小系统,麻雀虽小五脏俱全呀,用到各种线程控制,串口控制等技术.其中串口控制最麻烦,因为继电器的响应很快,根据不同的转接口,返回的数据质量是不一样的,所以不能直接wirte,然后马上read ...

  5. Problem O: 逆序输出——C语言初学者百题大战之二十

    #include<stdio.h> int main() { int a,b,c,d,e,n; scanf("%d",&n); a=n/; b=n%/; c=n ...

  6. 输入参数之POJO包装类

    1,包装类:需要实现序列化 package com.songyan.pojo; import java.io.Serializable; public class QueryVo implements ...

  7. Swift开发经验——外部参数名

    一.什么是外部参数名? 浅显地说,外部参数名就是在调用一个方法时要在方法的参数前面加上一个特定的名字,目的是便于阅读代码,提高维护效率.   二.在最新的Xcode中,外部参数名的性质与用法如下 性质 ...

  8. Android UI Material Design

    Material Design 中文版: http://wiki.jikexueyuan.com/project/material-design/ Material Design开发文章系列1:App ...

  9. S3C2440的存储器映射(27根地址线如何寻找1G的地址)

    转:http://blog.csdn.net/ce123_zhouwei/article/details/6882091 查S3C2440的数据手册可知S3C2440可寻址1G的地址范围,但是S3C2 ...

  10. golangWEB框架gin学习之获取post参数

    原文地址:http://www.niu12.com/article/41 package main import ( "fmt" "github.com/gin-goni ...