mysql dbnull_因DataTable的字段值为DBNull引发的异常 | 学步园

1 问题重现

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

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

6e87c3d2b03973bd63406fef27d2270c.png

(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)运行代码,抛出如下图所示异常。

a1404897c86ac6629daa0e21ae0cc80a.png

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表的数据,如下图所示。

76724dbcc12389ea699da94311331c4e.png

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

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

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

37a41d34e32008f14440c1ead38df65c.png

[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();

再次执行程序,得到下面想要的结果。

51db6cac11e40ec903eacf09c1ecb212.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值