zoukankan      html  css  js  c++  java
  • 因DataTable的字段值为DBNull引发的异常

    问题重现

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

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

     

    (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)执行代码,抛出例如以下图所看到的异常。

     

    问题分析与解决

    从异常提示信息能够看出,问题出在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。为什么不这样做。就不去瞎推測了。

    找到解决方法要紧。

    解决方法

    我们除了使用“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();

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

     

  • 相关阅读:
    定位的原理
    UE4 开发三维GIS 一 场景光影
    UE4 开发三维GIS
    hive
    atlas
    开源AI药物发现TorchDrug安装测试的那些坑
    使用Docker快速搭建zabbix 5
    Docker简易部署
    简单的批量telnet 测试
    ASP.NET Core 中间件
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/6772417.html
Copyright © 2011-2022 走看看