Chuyện gì đang xảy ra trong đó?
Bạn trích dẫn danh sách tham số cho một số quá tải của Add
. Đây là các phương thức tiện lợi tương ứng trực tiếp với quá tải hàm tạo cho SqlParameter
lớp. Về cơ bản, chúng xây dựng đối tượng tham số bằng cách sử dụng bất kỳ hàm tạo nào có cùng chữ ký với phương thức tiện lợi mà bạn đã gọi, sau đó gọi SqlParameterCollection.Add(SqlParameter)
như thế này:
SqlParameter foo = new SqlParameter(parameterName, dbType, size);
this.Add(foo);
AddWithValue
là tương tự nhưng thuận tiện hơn nữa, cũng đặt giá trị. Tuy nhiên, nó thực sự được giới thiệu để giải quyết một lỗ hổng khung. Để trích dẫn MSDN,
Quá tải của
Add
điều đó cần đến tính năng cắt và một đối tượng không được dùng nữa vì có thể có sự mơ hồ vớiSqlParameterCollection.Add
quá tải sẽ lấy mộtString
và mộtSqlDbType
giá trị liệt kê trong đó việc truyền aninteger với chuỗi có thể được hiểu là giá trị tham số hoặcSqlDbType
tương ứng giá trị. Sử dụngAddWithValue
bất cứ khi nào bạn muốn thêm một tham số bằng cách chỉ định tên và giá trị của nó.
Hàm tạo quá tải cho SqlParameter
lớp chỉ là những tiện ích để thiết lập các thuộc tính cá thể. Chúng rút ngắn mã, với tác động nhỏ đến hiệu suất:phương thức khởi tạo có thể bỏ qua các phương thức setter và hoạt động trực tiếp trên các thành viên riêng. Nếu có sự khác biệt thì sẽ không nhiều.
Tôi nên làm gì?
Lưu ý những điều sau (từ MSDN)
Đối với tham số đầu ra và tham số hai chiều cũng như giá trị trả về, bạn phải đặt giá trị của
Size
. Điều này không bắt buộc đối với các tham số đầu vào và nếu không được đặt rõ ràng, giá trị được suy ra từ kích thước thực của tham số đã chỉ định khi câu lệnh aparameterized được thực thi.
Loại mặc định là đầu vào. Tuy nhiên, nếu bạn cho phép kích thước được suy ra như vậy và bạn tái chế đối tượng tham số trong một vòng lặp (bạn đã nói rằng bạn quan tâm đến hiệu suất) thì kích thước sẽ được đặt bởi giá trị đầu tiên và bất kỳ giá trị tiếp theo nào dài hơn sẽ được cắt bớt. Rõ ràng điều này chỉ có ý nghĩa đối với các giá trị có độ dài thay đổi như chuỗi.
Nếu bạn đang truyền nhiều lần cùng một tham số logic trong một vòng lặp, tôi khuyên bạn nên tạo một đối tượng SqlParameter bên ngoài vòng lặp và kích thước nó một cách thích hợp. Định cỡ quá mức một varchar là vô hại, vì vậy nếu đó là PITA để đạt được mức tối đa chính xác, chỉ cần đặt nó lớn hơn bạn mong đợi cột. Bởi vì bạn đang tái chế đối tượng thay vì tạo một đối tượng mới cho mỗi lần lặp, mức tiêu thụ bộ nhớ trong suốt thời gian của vòng lặp có thể sẽ giảm ngay cả khi bạn có một chút hào hứng với kích thước quá khổ.
Sự thật mà nói, trừ khi bạn xử lý hàng nghìn cuộc gọi, không điều nào trong số này sẽ tạo ra nhiều khác biệt. AddWithValue
tạo một đối tượng mới, vượt qua vấn đề định cỡ. Nó ngắn gọn, ngọt ngào và dễ hiểu. Nếu bạn lặp lại hàng nghìn, hãy sử dụng cách tiếp cận của tôi. Nếu bạn không, hãy sử dụng AddWithValue
để giữ cho mã của bạn đơn giản và dễ bảo trì.
2008 đã lâu rồi
Trong những năm kể từ khi tôi viết bài này, thế giới đã thay đổi. Có những loại ngày tháng mới, và cũng có một vấn đề tôi không nghĩ đến cho đến khi một vấn đề gần đây về ngày tháng khiến tôi nghĩ về hệ quả của việc mở rộng.
Mở rộng và thu hẹp, đối với những người không quen với các thuật ngữ, là những phẩm chất của chuyển đổi loại dữ liệu. Nếu bạn gán một số nguyên cho một giá trị kép, thì sẽ không bị mất độ chính xác bởi vì giá trị kép là "rộng hơn". Luôn luôn an toàn để làm điều này, vì vậy chuyển đổi là tự động. Đây là lý do tại sao bạn có thể gán một int cho double nhưng theo cách khác, bạn phải thực hiện một phép ép kiểu rõ ràng - double sang int là một chuyển đổi thu hẹp với khả năng mất độ chính xác.
Điều này có thể áp dụng cho các chuỗi:NVARCHAR rộng hơn VARCHAR, vì vậy bạn có thể gán một VARCHAR cho một NVARCHAR nhưng theo cách khác thì yêu cầu ép kiểu. So sánh hoạt động vì VARCHAR ngầm mở rộng thành NVARCHAR, nhưng điều này sẽ cản trở việc sử dụng các chỉ mục!
Các chuỗi C # là Unicode, vì vậy AddWithValue sẽ tạo ra một tham số NVARCHAR. Ở đầu kia, các giá trị cột VARCHAR mở rộng thành NVARCHAR để so sánh. Điều này không dừng việc thực thi truy vấn nhưng nó ngăn các chỉ mục được sử dụng. Tệ thật.
Bạn có thể làm gì về nó? Bạn có hai giải pháp khả thi.
- Nhập tham số một cách rõ ràng. Điều này có nghĩa là không còn AddWithValue
- Thay đổi tất cả các loại cột chuỗi thành NVARCHAR.
Bỏ VARCHAR có lẽ là ý tưởng tốt nhất. Đó là một thay đổi đơn giản với những hậu quả có thể dự đoán được và nó cải thiện câu chuyện bản địa hóa của bạn. Tuy nhiên, bạn có thể không có tùy chọn này.
Những ngày này tôi không thực hiện nhiều ADO.NET trực tiếp. Linq2Sql hiện là vũ khí lựa chọn của tôi và hành động viết bản cập nhật này khiến tôi băn khoăn không biết nó xử lý vấn đề này như thế nào. Tôi đột ngột có mong muốn cháy bỏng là kiểm tra mã truy cập dữ liệu của mình để tra cứu qua các cột VARCHAR.
2019 và thế giới đã lại
Linq2Sql không có sẵn trong dotnet Core, vì vậy tôi thấy mình đang sử dụng Dapper. Vấn đề [N] VARCHAR vẫn còn là một vấn đề nhưng cho đến nay nó không còn bị chôn vùi nữa. Tôi tin rằng người ta cũng có thể sử dụng ADO để mọi thứ trở nên hoàn chỉnh về mặt đó.