【问题标题】:Trouble with Nullable Types, DBNulls and Data Rows可空类型、DBNulls 和数据行的问题
【发布时间】:2010-10-28 21:07:01
【问题描述】:

我在 Stack Overflow 上看到 this thread 关于在 DBNull 和可空类型之间进行转换,但我仍然感到困惑。我已经编写了这样的代码,其中包含一些 hack 代码来处理 DateTime 和 ints 的可为空类型,我将在下面显示,但它很混乱,我想使用 Nullable 类型:

 DataTable dt = ds.Tables[0];
 List<RON> list = (from dr in dt.AsEnumerable()
                              select new RON
                              {
                                  RONId = dr[0].ToString(),
                                  StaffNumber = dr[1].ToString(),
                                  CheckInDate = GetCheckInDate(dr[2]),
                                  NonMissionIndicator = dr[3].ToString(),
                                  Comments = dr[4].ToString(),
                                  NonComplyIndicator = dr[5].ToString(),
                                  LOAirport = dr[6].ToString(),
                                  RONAirport = dr[7].ToString(),
                                  PropertyId = GetPropertyId(dr[8]),
                                  PropertyChain = dr[9].ToString(),
                                  PropertyName = dr[10].ToString(),
                                  PropertyStreet = dr[11].ToString(),
                                  PropertyStreet2 = dr[12].ToString(),
                                  PropertyCity = dr[13].ToString(),
                                  PropertyState = dr[14].ToString(),
                                  PropertyPostalCode = dr[15].ToString(),
                                  PropertyPhone = dr[16].ToString(),
                                  FAX = dr[17].ToString(),
                                  PropertyCountry = dr[18].ToString(),
                                  PropertyLongitude = GetPropertyLongitude(dr[19]),
                                  PropertyLatitude = GetPropertyLatitude(dr[20]),
                                  PropertyAirport = dr[21].ToString(),
                                  ReportedBy = dr[22].ToString(),
                                  ReportedDTS= GetReportedByDate(dr[23]),
                                  CanceledBy = dr[24].ToString(),
                                  CanceledDTS = GetCanceledByDate(dr[25])
                              }).ToList();
            return list;
        }

        //TODO: Change Defaukt date
        private static DateTime GetCheckInDate(object checkInDate)
        {
            return checkInDate == DBNull.Value ? new DateTime(2000, 1, 1, 00, 00, 00) : Convert.ToDateTime(checkInDate);
        }

        //TODO: Change Defaukt date
        private static DateTime GetReportedByDate(object reportedByDate)
        {
            return reportedByDate == DBNull.Value ? new DateTime(2000, 1, 1, 00, 00, 00) : Convert.ToDateTime(reportedByDate);
        }

        //TODO: Change Defaukt date
        private static DateTime GetCanceledByDate(object canceledByDate)
        {
            return canceledByDate == DBNull.Value ? new DateTime(2000, 1, 1, 00, 00, 00) : Convert.ToDateTime(canceledByDate);
        }

        private static Int32 GetPropertyId(object propertyId)
        {
            return propertyId == DBNull.Value ? 0 : Convert.ToInt32(propertyId);
        }

        private static double GetPropertyLongitude(object propertyLongitude)
        {
            return propertyLongitude == DBNull.Value ? 0.0 : Convert.ToDouble(propertyLongitude);
        }

        private static double GetPropertyLatitude(object propertyLatitude)
        {
            return propertyLatitude == DBNull.Value ? 0.0 : Convert.ToDouble(propertyLatitude);
        }

RON 现在定义为:

public class RON
    {
        public string RONId { get; set; }
        public string StaffNumber { get; set; }
        public DateTime CheckInDate { get; set; }
        public string NonMissionIndicator { get; set; }
        public string NonComplyIndicator { get; set; }
        public string LOAirport { get; set; }
        public string RONAirport { get; set; }
        public int PropertyId { get; set; }
        public string PropertyChain { get; set; }
        public string PropertyName { get; set; }
        public string PropertyStreet { get; set; }
        public string PropertyStreet2 { get; set; }
        public string PropertyCity { get; set; }
        public string PropertyState { get; set; }
        public string PropertyPostalCode { get; set; }
        public string PropertyCountry { get; set; }
        public string PropertyPhone { get; set; }
        public string FAX { get; set; }
        public double PropertyLongitude { get; set; }
        public double PropertyLatitude { get; set; }
        public string PropertyAirport { get; set; }
        public string ReportedBy { get; set; }
        public DateTime ReportedDTS { get; set; }
        public string CanceledBy { get; set; }
        public DateTime CanceledDTS { get; set; }
        public string Comments { get; set; }

数据库的人告诉我,这是从 Oracle 的数据集/游标返回:

 RON_ID                                    NOT NULL VARCHAR2(40)
 STAFF_NUM                                 NOT NULL VARCHAR2(12)
 CHECKIN_DATE                              NOT NULL DATE
 NONMISSION_IND                            NOT NULL VARCHAR2(1)
 COMMENTS                                           VARCHAR2(4000)
 NONCOMPLY_IND                                      VARCHAR2(4000)
 PROPERTY_ID                               NOT NULL NUMBER(38)
 PROPERTY_CHAIN                                     VARCHAR2(2)
 PROPERTY_NAME                                      VARCHAR2(255)
 RON_AIRPORT                               NOT NULL VARCHAR2(3)
 PROPERTY_STREET                                    VARCHAR2(255)
 PROPERTY_STREET2                                   VARCHAR2(255)
 PROPERTY_CITY                                      VARCHAR2(255)
 PROPERTY_STATE                                     VARCHAR2(3)
 PROPERTY_POSTALCODE                                VARCHAR2(255)
 PROPERTY_PHONE                                     VARCHAR2(20)
 PROPERTY_FAX                                       VARCHAR2(20)
 PROPERTY_COUNTRY                                   VARCHAR2(2)
 PROPERTY_LONGITUDE                                 NUMBER
 PROPERTY_LATITUDE                                  NUMBER
 PROPERTY_AIRPORT                                   VARCHAR2(3)
 REPORTED_BY                                        VARCHAR2(50)
 REPORTED_DTS                              NOT NULL DATE
 CANCELED_BY                                        VARCHAR2(50)
 CANCELED_DTS                                       DATE

如何使用 Nullable 类型声明 RON 以及如何使用 Nullable Dates 等进行操作?必须检查字符串吗?

【问题讨论】:

    标签: c# dataset nullable


    【解决方案1】:

    要将值类型(例如 DateTime)定义为 Nullable...请执行以下操作之一:

    DateTime? ReportedDTS
    

    Nullable<DateTime> ReportedDTS
    

    引用类型(如字符串)已经是“可空的”。

    要从 DataRow 中获取可为空的值,您可以使用字段扩展方法:

    DateTime? nullableDate = dataRow.Field<DateTime?>("ColumnName");
    

    这会自动将 DBNull 转换为 null。

    因此,对于您的示例,您可以执行以下操作:

    select new RON
               {
                   RONId = dr.Field<string>("RON_ID"),
                   // snip...
                   CheckInDate = dr.Field<DateTime?>("CHECKIN_DATE"),
                   // snip...
               };
    

    【讨论】:

    • 谢谢!那么日期时间? nullableDate = dataRow.Field("ColumnName");在我的例子中会是什么?
    • 我得到一个“指定的转换无效。”} [System.InvalidCastException]:{“指定的转换无效。”} 数据:{System.Collections.ListDictionaryInternal} HelpLink:null InnerException: null 消息:“指定的演员表无效。”来源:“System.Data.DataSetExtensions” StackTrace:“在 System.Data.DataRowExtensions.UnboxT`1.NullableField[TElem](Object value)\r\n at System.Data.DataRowExtensions.Field[T](Da跨度>
    • ...当尝试执行 CheckInDate = dr.Field("CHECKIN_DATE"),在将字段定义为 DateTime 之后?
    • 嗯......仔细看看你的例子,架构说 CHECKIN_DATE 被定义为 NOT NULL。无需将其更改为可为空,因为它在数据库中永远不能为 NULL。
    • 所以 Canceled_DTS 是我唯一需要担心的字段
    【解决方案2】:

    在查看您的原始问题时,我发现当 .ToString() 对空值调用时会发生错误。

    当数据集字段具有 DBNULL 值时会发生这种情况。
    最好的方法是在调用对象上的任何方法之前先测试 null。
    即

    DataTable dt = ds.Tables[0]; List<RON> list = (from dr in dt.AsEnumerable() select new RON { RONId = dr.IsNull("RONid") ? "0" : dr.Field<String>("RONid"), StaffNumber = dr.IsNull("StaffNumber") ? "0" : dr.Field<String>("StaffNumber"), ... etc, ... etc }).ToList(); return list; }

    PS:

    • 探测数据集以查找要匹配的字段值。在这里,我假设您的数据集“ColumnName”与传递给它的变量同名,但情况并非总是如此。
    • 忠告,使用“ColumnName”而不是索引,因为索引可能会在 db 更改、存储过程或查询更改时发生更改。

    【讨论】:

      【解决方案3】:

      由于只能将值类型设为Nullable,因此您不必为字符串做任何特殊的事情。原始类型(和DateTime)可以通过在类型名称后附加一个问号来声明为空,例如int? NullableNumber { get; set; }

      【讨论】:

      • 谢谢,我就是这么想的
      【解决方案4】:

      在分配 DateTime 或 null 之前,您可能需要与 DBNull 进行比较

      myNullableDate = (DBNull.Value == list.Field<object>("FOO"))
                ? null 
                : (DateTime?)list.Field<DateTime?>("FOO");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-24
        相关资源
        最近更新 更多