Ngoại lệ khi tham số AddWithValue là NULL


89

Tôi có mã sau để chỉ định các tham số cho truy vấn SQL. Tôi nhận được ngoại lệ sau khi tôi sử dụng Code 1; nhưng hoạt động tốt khi tôi sử dụng Code 2. Trong Code 2chúng tôi có một kiểm tra cho null và do đó một if..elsekhối.

Ngoại lệ:

Truy vấn được tham số hóa '(@application_ex_id nvarchar (4000)) SELECT E.application_ex_id A' yêu cầu tham số '@application_ex_id' không được cung cấp.

Mã 1 :

command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);

Mã 2 :

if (logSearch.LogID != null)
{
         command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
}
else
{
        command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
}

CÂU HỎI

  1. Bạn có thể vui lòng giải thích tại sao nó không thể lấy NULL từ giá trị logSearch.LogID trong Mã 1 (nhưng có thể chấp nhận DBNull) không?

  2. Có mã nào tốt hơn để xử lý điều này không?

Tham khảo :

  1. Gán null cho một SqlParameter
  2. Loại dữ liệu được trả về thay đổi tùy theo dữ liệu trong bảng
  3. Lỗi chuyển đổi từ cơ sở dữ liệu smallint thành C # nullable int
  4. Điểm của DBNull là gì?

    public Collection<Log> GetLogs(LogSearch logSearch)
    {
        Collection<Log> logs = new Collection<Log>();

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();

            string commandText = @"SELECT  *
                FROM Application_Ex E 
                WHERE  (E.application_ex_id = @application_ex_id OR @application_ex_id IS NULL)";

            using (SqlCommand command = new SqlCommand(commandText, connection))
            {
                command.CommandType = System.Data.CommandType.Text;

                //Parameter value setting
                //command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                if (logSearch.LogID != null)
                {
                    command.Parameters.AddWithValue("@application_ex_id", logSearch.LogID);
                }
                else
                {
                    command.Parameters.AddWithValue("@application_ex_id", DBNull.Value );
                }

                using (SqlDataReader reader = command.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        Collection<Object> entityList = new Collection<Object>();
                        entityList.Add(new Log());

                        ArrayList records = EntityDataMappingHelper.SelectRecords(entityList, reader);

                        for (int i = 0; i < records.Count; i++)
                        {
                            Log log = new Log();
                            Dictionary<string, object> currentRecord = (Dictionary<string, object>)records[i];
                            EntityDataMappingHelper.FillEntityFromRecord(log, currentRecord);
                            logs.Add(log);
                        }
                    }

                    //reader.Close();
                }
            }
        }

        return logs;
    }

3
Ý bạn là gì tốt hơn? Mã 2 là cách chính xác để gửi giá trị null đến cơ sở dữ liệu.
Phil Gan

Câu trả lời:


148

Khó chịu phải không.

Bạn có thể dùng:

command.Parameters.AddWithValue("@application_ex_id",
       ((object)logSearch.LogID) ?? DBNull.Value);

Hoặc cách khác, sử dụng một công cụ như "dapper", nó sẽ làm tất cả những điều đó cho bạn.

Ví dụ:

var data = conn.Query<SomeType>(commandText,
      new { application_ex_id = logSearch.LogID }).ToList();

Tôi muốn thêm một phương thức vào dapper để có được IDataReader... thực sự không chắc liệu đó có phải là một ý tưởng hay không.


1
Tôi đã nghĩ đến một phần mở rộng về Parameterstài sản - đó có phải là một Object?
Phil Gan

6
@Phil hmmm, đúng vậy, và tôi hiểu ý bạn ... có thểAddWithValueAndTreatNullTheRightDamnedWay(...)
Marc Gravell

1
@MarcGravell Bạn có thể vui lòng giải thích tại sao nó không thể lấy NULL từ giá trị logSearch.LogID trong Mã 1 (nhưng có thể chấp nhận DBNull) không?
LCJ

18
@Lijo vì nulltrong giá trị tham số có nghĩa là "không gửi tham số này". Tôi nghi ngờ đó là một quyết định tồi mà chỉ đơn giản bị nướng trong Trong thực tế, tôi nghĩ vậy. Nhất của DBNulllà một quyết định về cơ bản xấu đó đã nướng trong: stackoverflow.com/a/9632050/23354
Marc Gravell

1
@tylerH vì quy tắc ép kiểu null coale - có thể đang suy yếu trong C # 9
Marc Gravell

52

Tôi thấy dễ dàng hơn khi chỉ viết một phương thức mở rộng cho các SqlParameterCollectiongiá trị xử lý null:

public static SqlParameter AddWithNullableValue(
    this SqlParameterCollection collection,
    string parameterName,
    object value)
{
    if(value == null)
        return collection.AddWithValue(parameterName, DBNull.Value);
    else
        return collection.AddWithValue(parameterName, value);
}

Sau đó, bạn chỉ cần gọi nó như:

sqlCommand.Parameters.AddWithNullableValue(key, value);

giá trị có thể là int hoặc int ?, string, bool hoặc bool ?, DateTime hoặc Datetime? , Vân vân ?
Kiquenet

3
Tôi đọc câu trả lời của Marc và nghĩ "Tôi nghĩ tôi chỉ muốn viết một phương thức mở rộng cho bộ sưu tập Tham số", sau đó tôi cuộn xuống một sợi tóc ... (điều thú vị về một phương pháp mở rộng là tôi có thể thực hiện một lần tìm / thay thế sau khi và tất cả các cập nhật mã của tôi được thực hiện)
jleach

1
Giải pháp tuyệt vời ... Các phương thức mở rộng phải được định nghĩa trong một lớp tĩnh. Làm thế nào để: Thực hiện và gọi một phương thức Tuỳ chỉnh mở rộng
Chris Catignani

2
Có lẽ tôi nhầm lẫn (loại C # newbie) nhưng bạn không thể làm điều đó chính xác hơn như thế này:return collection.AddWithValue(parameterName, value ?? DBNull.Value);
Tobias Feil

1
@TobiasFeil Có, bạn cũng có thể làm điều đó. Nó chỉ là một vấn đề của hương vị.
AxiomaticNexus

4

Đề phòng trường hợp bạn đang thực hiện việc này trong khi gọi một thủ tục được lưu trữ: Tôi nghĩ sẽ dễ đọc hơn nếu bạn khai báo giá trị mặc định trên tham số và chỉ thêm nó khi cần thiết.

SQL:

DECLARE PROCEDURE myprocedure
    @myparameter [int] = NULL
AS BEGIN

C #:

int? myvalue = initMyValue();
if (myvalue.hasValue) cmd.Parameters.AddWithValue("myparamater", myvalue);

0

một số vấn đề, được phép với Cần thiết đặt SQLDbType

command.Parameters.Add("@Name", SqlDbType.NVarChar);
command.Parameters.Value=DBNull.Value

nơi bạn nhập SqlDbType.NVarChar. Nhất thiết phải đặt kiểu SQL.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.