2010-04-08 34 views
27

tôi đã mệt mỏi viết đoạn mã sau:Làm thế nào để parameterize một chuỗi null với DBNull.Value rõ ràng và nhanh chóng

/* Commenting out irrelevant parts 
public string MiddleName; 
public void Save(){ 
    SqlCommand = new SqlCommand(); 
    // blah blah...boring INSERT statement with params etc go here. */ 
    if(MiddleName==null){ 
     myCmd.Parameters.Add("@MiddleName", DBNull.Value); 
    } 
    else{ 
     myCmd.Parameters.Add("@MiddleName", MiddleName); 
    } 
    /* 
    // more boring code to save to DB. 
}*/ 

Vì vậy, tôi đã viết này:

public static object DBNullValueorStringIfNotNull(string value) 
{ 
    object o; 
    if (value == null) 
    { 
     o = DBNull.Value; 
    } 
    else 
    { 
     o = value; 
    } 
    return o; 
} 

// which would be called like: 
myCmd.Parameters.Add("@MiddleName", DBNullValueorStringIfNotNull(MiddleName)); 

Nếu đây là một cách tốt để đi về việc này sau đó những gì bạn sẽ đề nghị như là tên phương pháp? DBNullValueorStringIfNotNull hơi tiết và khó hiểu.

Tôi cũng sẵn sàng giải quyết vấn đề này hoàn toàn. Tôi muốn làm điều này:

myCmd.Parameters.Add("@MiddleName", MiddleName==null ? DBNull.Value : MiddleName); 

nhưng điều đó sẽ không hoạt động vì "Nhà điều hành"? ' không thể áp dụng cho các toán hạng kiểu 'string và' System.DBNull '".

Tôi đã có C# 3.5 và SQL Server 2005 theo ý của mình nếu có vấn đề.

+0

tôi sẽ không viết các trường hợp null ở tất cả - nếu giá trị là null, bỏ qua từ báo cáo kết quả chèn. –

+0

nhưng điều đó sẽ không hoạt động. - hãy cụ thể, tại sao mọi người nên đoán? – Andrey

+1

@Andrey: tuyên bố của ông sẽ không biên dịch (trình biên dịch sẽ nói rằng không có chuyển đổi ngầm giữa 'DBNull' và' string'). –

Trả lời

47

Truyền một trong các giá trị của bạn thành object và nó sẽ biên dịch.

myCmd.Parameters.Add("@MiddleName", MiddleName==null ? (object)DBNull.Value : MiddleName); 
+10

Ngọt ngào: 'MiddleName ?? (đối tượng) DBNull.Value' hoạt động! Hoặc tốt hơn là 'public static readonly object DBNullValue = (object) DBNull.Value;' với 'MiddleName ?? DBNullValue'! Bạn là người hùng của tôi. –

+0

Argh, tôi phải đợi thêm 3 phút trước khi tôi có thể chấp nhận câu trả lời của bạn. –

+0

@David: Rất tuyệt! Thậm chí đã không được coi là coalescing. Tôi sẽ phải bắt đầu làm điều đó trong mã của tôi. Tôi nghĩ về caching giá trị như bạn mô tả, nhưng muốn giữ mã vào một dòng. –

1

Yeap, chúng tôi đều thích làm myCmd.Parameters.Add("@MiddleName", MiddleName ?? DBNull.Value);. Hoặc vẫn tốt hơn, có lớp SqlClient freakin hiểu rằng CLR null nên được ánh xạ tới DBNull.Value khi thêm tham số. Thật không may là hệ thống kiểu .Net đóng thay thế đầu tiên, và việc thực hiện SqlClient đóng thứ hai.

Tôi muốn sử dụng tên chức năng nổi tiếng, chẳng hạn như Coalesce hoặc IsNull. Bất kỳ nhà phát triển DB nào cũng sẽ nhận ra những gì họ làm ngay lập tức, từ tên riêng.

+1

Có những lý do chính đáng mà 'null' không ánh xạ tới' DBNull.Value'. Cụ thể là nó buộc bạn gán một giá trị cho mỗi tham số, ngay cả khi "giá trị" đó là một giá trị null của cơ sở dữ liệu. –

+0

Hơn nữa, có khả năng làm chuỗi ?? DBNull.Value có thể là tốt đẹp cho trường hợp cụ thể này, bạn phải xem xét vấn đề từ một phối cảnh trình biên dịch: kiểu trả về của biểu thức đó là gì? Trình biên dịch có nên tìm kiếm tổ tiên chung nhất, ngay cả khi nó là 'đối tượng'? –

+0

Có lẽ tôi không hiểu rõ ý nghĩa của 'hệ thống kiểu CLR': sự không thể thiết lập kiểu thời gian biên dịch của biểu thức '(type1 ?? type2)'. Chúng tôi đang nói điều tương tự. –

11

Cá nhân này là những gì tôi sẽ làm gì với một phương pháp mở rộng (đảm bảo điều này đi vào một lớp tĩnh)

public static object GetStringOrDBNull(this string obj) 
{ 
    return string.IsNullOrEmpty(obj) ? DBNull.Value : (object) obj 
} 

Sau đó, bạn sẽ phải

myCmd.Parameters.Add("@MiddleName", MiddleName.GetStringOrDBNull()); 
+0

Tôi thích tên. Vì vậy, +1 cho điều đó. Tôi thích giải pháp của câu trả lời được chấp nhận tốt hơn mặc dù. :-) –

+4

Xem liệu bạn có thay đổi ý định sau khi thay vì có 100 câu lệnh nếu bạn có 100 toán tử bậc ba không. –

+2

Tôi thực sự đang sử dụng toán tử kết hợp rỗng. Bạn phải đồng ý rằng 'MiddleName ?? DBNullValue' khá dễ darn. Nhưng +1 cho bình luận của bạn quá. –

1

Tôi thà cung cấp cho bạn hai đề xuất hoàn toàn khác nhau:

  1. Sử dụng ORM. Có rất nhiều công cụ ORM không xâm nhập.

  2. Viết trình bao bọc của riêng bạn để tạo các lệnh, với giao diện rõ ràng hơn.Một cái gì đó như:

    public class MyCommandRunner { 
        private SqlCommand cmd; 
    
        public MyCommandRunner(string commandText) { 
        cmd = new SqlCommand(commandText); 
        } 
    
        public void AddParameter(string name, string value) { 
        if (value == null) 
        cmd.Parameters.Add(name, DBNull.Value); 
        else 
         cmd.Parameters.Add(name, value); 
        } 
    
        // ... more AddParameter overloads 
    } 
    

Nếu bạn đổi tên AddParameter phương pháp của bạn chỉ Add, bạn có thể sử dụng nó trong một cách rất trơn:

var cmd = new MyCommand("INSERT ...") 
    { 
    { "@Param1", null }, 
    { "@Param2", p2 } 
    }; 
+0

+1 cho ý tưởng này. Tôi có thể xem xét điều này trong tương lai. –

1

tôi sẽ đề nghị sử dụng tài sản nullable thay vì các lĩnh vực công cộng và phương pháp 'AddParameter' (không biết mã này có được tối ưu hóa hay chính xác hay không, chỉ cần thoát khỏi đầu của tôi):


private string m_MiddleName; 

public string MiddleName 
{ 
    get { return m_MiddleName; } 
    set { m_MiddleName = value; } 
} 

. 
. 
. 

public static void AddParameter(SQLCommand cmd, string parameterName, SQLDataType dataType, object value) 
{ 
    SQLParameter param = cmd.Parameters.Add(parameterName, dataType); 

    if (value is string) { // include other non-nullable datatypes 
    if (value == null) { 
     param.value = DBNull.Value; 
    } else { 
     param.value = value; 
    } 
    } else { 

    // nullable data types 
    // UPDATE: HasValue is for nullable, not object type 
    if (value.HasValue) // {{{===================================================== 
    { 
      param.value = value; 
    } else 
    { 
      param.value = DBNull.Value; 
    } 
    } 
} 

. 
. 
. 
AddParameter(cmd, "@MiddleName", SqlDbType.VarChar, MiddleName); 

+0

giá trị.HasValue không biên dịch: HasValue là cho nullable , không phải loại đối tượng – Kiquenet

2

@David Cảm ơn đề xuất của bạn. Các phương pháp sau đây hoạt động tuyệt vời!

MiddleName ?? (object)DBNull.Value 
14

Bạn có thể tránh các diễn viên rõ ràng để object sử dụng SqlString.Null thay vì DBNull.Value:

MiddleName ?? SqlString.Null 

Có nhiều loại tương ứng cho int, datetime, và vân vân. Dưới đây là một đoạn mã với một vài chi tiết ví dụ:

cmd.Parameters.AddWithValue("@StartDate", StartDate ?? SqlDateTime.Null); 
cmd.Parameters.AddWithValue("@EndDate", EndDate ?? SqlDateTime.Null); 
cmd.Parameters.AddWithValue("@Month", Month ?? SqlInt16.Null); 
cmd.Parameters.AddWithValue("@FormatID", FormatID ?? SqlInt32.Null); 
cmd.Parameters.AddWithValue("@Email", Email ?? SqlString.Null); 
cmd.Parameters.AddWithValue("@ZIP", ZIP ?? SqlBoolean.Null); 
6
myCmd.Parameters.Add("@MiddleName", MiddleName ?? (object)DBNull.Value); 
Các vấn đề liên quan