2012-02-29 23 views
12

Cơ sở dữ liệu SQL Server của tôi chứa các giá trị DateTime không có giá trị. Làm thế nào tôi có thể chuyển đổi chúng thành một đối tượng DateTime nullable trong ứng dụng của tôi trong C#?Làm thế nào để có được DateTime vô hiệu hóa trong cơ sở dữ liệu

Đây là những gì tôi nghĩ rằng nó sẽ như thế nào, nhưng nó không:

DateTime? dt = (DateTime?) sqldatareader[0]; 
+1

Làm thế nào nó không hoạt động? Bạn có ngoại lệ không? – jrummell

+1

Vui lòng không thêm tiền tố vào tiêu đề của bạn bằng thẻ. Có thẻ cho một lý do. – cadrell0

Trả lời

21

Một SQL null là không giống như một null .NET; bạn phải so sánh với System.DBNull.Value:

object sqlDateTime = sqldatareader[0]; 
DateTime? dt = (sqlDateTime == System.DBNull.Value) 
    ? (DateTime?)null 
    : Convert.ToDateTime(sqlDateTime); 

Trong câu trả lời cho bình luận của bạn, kiểu dữ liệu của Item tài sản của một DataReader là của các loại cơ sở dữ liệu cơ bản. Có thể là System.Data.SqlTypes.SqlDateTime cho cơ sở dữ liệu SQL Server không rỗng hoặc System.DBNull cho cột rỗng hoặc System.Data.Odbc.OdbcTypes.SmallDateTime cho cơ sở dữ liệu ODBC hoặc thực sự là về bất kỳ thứ gì. Điều duy nhất bạn có thể dựa vào là nó thuộc loại object.

Đây cũng là lý do tôi đề xuất sử dụng Convert.ToDateTime() thay vì loại cưỡng chế DateTime. Không có sự đảm bảo nào về ODBC hoặc bất kỳ cột ngày tháng nào có thể bị ép buộc thành .NET DateTime. Tôi lưu ý bình luận của bạn chỉ định một "sqldatareader", và một máy chủ SQL System.Data.SqlTypes.SqlDateTime thực sự có thể bị ép buộc đến một số System.DateTime, nhưng câu hỏi ban đầu của bạn không cho chúng ta biết điều đó.

Để biết thêm thông tin về cách sử dụng DataReader s, tham khảo MSDN.

2

Bạn cần kiểm tra xem giá trị "là DBNull" chứ không phải chỉ là null. Tôi gửi một lớp helper nhỏ trên blog của tôi: http://improve.dk/archive/2007/10/08/handling-dbnulls.aspx

Khi bạn thực hiện các lớp, bạn sử dụng nó như thế này:

DateTime? dt = DBConvert.To<datetime?>(sqldatareader[0]); 
+0

Tâm trí tuyệt vời nghĩ [chủ yếu] giống nhau! B^D –

0
DateTime? dt = null; 

if (sqldatareader[0] != System.DbNull.Value) 
{ 
    dt = (DateTime)sqldatareader[0]; 
} 
1

Một thời gian trước, tôi đã viết một loạt các phương pháp khuyến nông cho một DataRow để làm chỉ là loại downcasting ... bởi vì tôi ghét viết ổ đĩa lặp đi lặp lại. Cách sử dụng rất đơn giản:

foreach(DataRow dr in someDataTable) 
{ 
    DateTime? dt = dr.CastAsDateTimeNullable("lastUpdated") ; 
    int  id = dr.CastAsInt("transactionID") ; 
    // etc. 
} 

Đây là phần dành cho giá trị ngày giờ. Việc thêm triển khai cho các loại dữ liệu khác sẽ khá nhỏ. Sẽ không khó để làm điều tương tự như vậy với một DataReader nếu một người bị nghiêng.

Tôi cố gắng để đưa ra phương pháp chung, nhưng những hạn chế trong cách generics được thực hiện xong việc đã gây khó khăn hoặc không thể làm gì và vẫn nhận được hành vi của tôi muốn (ví dụ, null giá trị chứ không phải là default(T) — giá trị mặc định nhận cho NULLs SQL điều đó sẽ tạo ra sự khác biệt giữa 0null ... khó khăn).

public static class DataRowExtensions 
{ 

    #region downcast to DateTime 

    public static DateTime CastAsDateTime(this DataRow row , int index) 
    { 
    return toDateTime(row[index]) ; 
    } 
    public static DateTime CastAsDateTime(this DataRow row , string columnName) 
    { 
    return toDateTime(row[columnName]) ; 
    } 

    public static DateTime? CastAsDateTimeNullable(this DataRow row , int index) 
    { 
    return toDateTimeNullable(row[index]); 
    } 
    public static DateTime? CastAsDateTimeNullable(this DataRow row , string columnName) 
    { 
    return toDateTimeNullable(row[columnName]) ; 
    } 

    #region conversion helpers 

    private static DateTime toDateTime(object o) 
    { 
    DateTime value = (DateTime)o; 
    return value; 
    } 

    private static DateTime? toDateTimeNullable(object o) 
    { 
    bool hasValue = !(o is DBNull); 
    DateTime? value = (hasValue ? (DateTime?) o : (DateTime?) null) ; 
    return value; 
    } 

    #endregion 

    #endregion downcast to DateTime 

    // ... other implementations elided .. for brevity 

} 
23

Gần đây tôi đã tìm thấy thủ thuật này, nó đơn giản:

DateTime? dt = sqldatareader[0] as DateTime?; 
+4

Không ngu ngốc khi trả lời câu hỏi của bạn. – Homer

+0

Điều này làm việc tuyệt vời cho tôi. – alundy

+0

Giải pháp chính xác rất đẹp! Tôi sẽ sử dụng điều này từ bây giờ thay vì phương pháp ternary cồng kềnh hơn. – Baxter

0

Chỉ cần sử dụng:

System.Nullable<System.DateTime> yourVariableName; 

Làm cho nó dễ dàng trên mình :)

+0

Điều này có liên quan gì với cơ sở dữ liệu? – deW1

0

thế nào về việc tạo ra phương pháp helper

private static DateTime? MyDateConverter(object o) 
{ 
    return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o); 
} 

Cách sử dụng

MyDateConverter(sqldatareader[0]) 
Các vấn đề liên quan