2010-08-17 4 views
10

Tôi thường xuyên phải đối phó với DataTables kết nối với điều khiển lưới, tùy chỉnh cập nhật luôn luôn dường như sản xuất rất nhiều mã liên quan đến DBNull.Value. Tôi nhìn thấy một câu hỏi tương tự ở đây nhưng nghĩ rằng phải có một câu trả lời tốt hơn:Đối phó với DBNull.Value

What is the best way to deal with DBNull's

Điều tôi thấy là tôi có xu hướng để đóng gói cập nhật cơ sở dữ liệu của tôi trong các phương pháp vì vậy tôi kết thúc với mã như dưới đây, nơi tôi di chuyển DBNull.value thành một loại nullable và sau đó trở lại để cập nhật:

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    Boolean? requiresSupport = null; 
    if (grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) != DBNull.Value) 
     requiresSupport = (bool)grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport); 

    AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport) 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID,    
     bool? requiresSupport) 
    { 
     List<SqlParameter> parameters = new List<SqlParameter>(); 

     parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
     parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 

     if (requiresSupport == null) 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = DBNull.Value }); 
     else 
      parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = requiresSupport }); 

     //execute sql query here to do update 
    } 

Đó chỉ là một ví dụ về dòng chảy và mã không hoạt động. Tôi nhận ra rằng tôi có thể làm những thứ như vượt qua đối tượng hoặc nuốt các vấn đề tiềm năng bằng cách sử dụng "như kiểu" để nhận DBUll thẳng tới null nhưng cả hai điều này với tôi đều ẩn chứa các lỗi tiềm ẩn, tôi thích kiểu an toàn của phương thức với các kiểu nullable.

Có phương pháp nào sạch hơn để thực hiện việc này trong khi vẫn duy trì an toàn loại không?

+0

Tại sao bạn không sử dụng trực tiếp mạnh mẽ DataRow? Bạn đã đề cập rằng bạn phải sử dụng DataTables. Nếu những bảng dữ liệu đó được đánh mạnh, bạn có thể gửi hàng dữ liệu đến phương thức của mình. Hàng dữ liệu đã sử dụng DBNull. –

Trả lời

14

Một vài phương pháp helper generic (rất) đơn giản ít nhất có thể tập trung kiểm tra vào một đoạn mã:

static T FromDB<T>(object value) 
{ 
    return value == DBNull.Value ? default(T) : (T)value; 
} 

static object ToDB<T>(T value) 
{ 
    return value == null ? (object) DBNull.Value : value; 
} 

Những phương pháp này sau đó có thể được sử dụng nếu phù hợp:

private void UpdateRowEventHandler(object sender, EventArgs e) 
{ 
    AdditionalSupport.UpdateASRecord(year, studentID, 
     FromDB<Boolean?>(grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport))); 
} 

internal static void UpdateASRecord(
     string year, 
     string studentID, 
     bool? requiresSupport) 
{ 
    List<SqlParameter> parameters = new List<SqlParameter>(); 

    parameters.Add(new SqlParameter("@year", SqlDbType.Char, 4) { Value = year }); 
    parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) { Value = studentID }); 
    parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) { Value = ToDB(requiresSupport) }); 

    //execute sql query here to do update 
} 
+2

Đề xuất sử dụng 'Convert.IsDBNull()' thay vì 'value == DBNull.Value'. Và 'FromDBNull' /' ToDBNull' thay vì chỉ FromDB'/'ToDB', có thể. – abatishchev

+0

Điều này có vẻ tidier nhờ tôi nghĩ generics có thể là con đường để đi Tôi sẽ sử dụng này trừ khi bất cứ ai đi kèm với một giải pháp tốt hơn. – PeteT

+1

@abatishchev: Có, sử dụng 'Convert.IsDBNull' có lẽ sẽ thanh lịch hơn; đóng gói thử nghiệm mà bản thân nó không hoàn toàn là mục đích của phương pháp. Về việc đặt tên tôi có thể đồng ý rằng 'FromDB' và' ToDB' là một chút ở phía ngắn, mặc dù tôi thà gọi các phương thức 'ToDBValue' và' FromDBValue' vì chúng không chuyển đổi tất cả các giá trị thành 'DBNull', nhưng thay vì trả về giá trị được truyền trong một biểu mẫu có thể sử dụng được khi gửi nó hoặc nhận nó từ DB. –

0
parameters.Add("@requires_support", SqlDbType.Bit).Value = (object)requiresSupport ?? DBNull.Value; 

có nghĩa là giống như

parameters.Add("@requires_support", SqlDbType.Bit).Value = (requiresSupport != null) ? (object)requiresSupport : DBNull.Value; 

hoặc

if (requiresSupport != null) 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = requiresSupport 
else 
    parameters.Add("@requires_support", SqlDbType.Bit).Value = DBNull.Value; 

(diễn viên bổ sung cho đối tượng là cần thiết để loại bỏ các loại nhập nhằng)

+0

@ petebob796: Giải pháp của tôi là thủy triều nhiều nhất, phải không? – abatishchev

1

Tôi không thấy có gì sai với as -casting và null coalescing.

as -casting được sử dụng cho việc đọc:

bool? requiresSupport = 
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
AdditionalSupport.UpdateASRecord(year, studentID, requiresSupport); 

null coalescing được sử dụng cho các văn bản:

parameters.Add(new SqlParameter("@student_id", SqlDbType.Char, 11) 
    { Value = studentID }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = (object)requiresSupport ?? DBNull.Value }); 

Cả hai trong số này là hoàn toàn typesafe và không "ẩn" lỗi.

Nếu bạn thực sự muốn, bạn thể quấn chúng thành phương pháp tĩnh, vì vậy bạn kết thúc với điều này để đọc:

//bool? requiresSupport = 
// grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport) as bool?; 
bool? requiresSupport = FromDBValue<bool?>(
    grdMainLevel1.GetFocusedRowCellValue(colASRequiresSupport)); 

và điều này cho viết:

//parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
// { Value = (object)requiresSupport ?? DBNull.Value }); 
parameters.Add(new SqlParameter("@requires_support", SqlDbType.Bit) 
    { Value = ToDBValue(requiresSupport) }); 

Phương pháp tĩnh mã là hơi sạch hơn trong trường hợp viết, nhưng ý định là ít rõ ràng (đặc biệt là trong trường hợp đọc).

0
public static object DbNullable<T>(T? value) where T : struct 
{ 
    if (value.HasValue) 
    { 
     return value.Value; 
    } 
    return DBNull.Value; 
} 

public static object ToDbNullable<T>(this T? value) where T : struct 
{ 
    return DbNullable(value); 
} 

Đây là việc triển khai trình trợ giúp DBNULL của tôi.Cách sử dụng rất đơn giản:

new SqlParameter("Option1", option1.ToDbNullable())