Проблема с обнуляемыми типами, DBNulls и строками данных - PullRequest
5 голосов
/ 29 октября 2010

Я видел этот поток в Переполнении стека относительно преобразования между типами DBNull и nullable, но я все еще в замешательстве. Я написал такой код с некоторым кодом для взлома, чтобы иметь дело с обнуляемыми типами для DateTime и int, которые я покажу ниже, но это беспорядок и я хочу использовать обнуляемые типы:

 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 в DataSet / курсор:

 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

Как я могу объявить RON с Nullable Types и как я могу выполнять операции с Nullable Dates и тому подобное? Нужно ли проверять строки?

Ответы [ 4 ]

7 голосов
/ 29 октября 2010

Чтобы определить тип значения (например, DateTime) как Nullable ..., выполните одно из следующих действий:

DateTime? ReportedDTS

ИЛИ

Nullable<DateTime> ReportedDTS

Типы ссылок (например, строка)уже "обнуляются".

Чтобы получить значение Nullable из DataRow, вы можете использовать метод расширения поля:

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

Это автоматически преобразует DBNull в ноль.

Так что для вашего примера вы можете сделать что-то вроде:

select new RON
           {
               RONId = dr.Field<string>("RON_ID"),
               // snip...
               CheckInDate = dr.Field<DateTime?>("CHECKIN_DATE"),
               // snip...
           };
1 голос
/ 24 декабря 2014

При рассмотрении вашего исходного вопроса я вижу, что произойдет ошибка при вызове .ToString () для нулевого значения.

This happens when the dataset field has a DBNULL value.
The Best approach is to test for null first before calling any methods on the object.
i.e.

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" вместо индекса, поскольку индекс может изменяться при изменении БД, сохраненного процесса или запроса.
0 голосов
/ 14 февраля 2013

Возможно, вам придется сравнить с DBNull перед назначением DateTime или null

myNullableDate = (DBNull.Value == list.Field<object>("FOO"))
          ? null 
          : (DateTime?)list.Field<DateTime?>("FOO");
0 голосов
/ 29 октября 2010

Поскольку могут быть заданы только типы значений Nullable, вам не нужно ничего делать для строк.Примитивные типы (и DateTime) могут быть объявлены обнуляемыми путем добавления знака вопроса после имени их типа, например int? NullableNumber { get; set; }.

...