Bạn thực sự có thể sử dụng if
, nhưng bạn cũng nên có thể sử dụng while
trong một trường hợp như thế này mà không có lỗi. Chỉ cần thay đổi nó thành if
sẽ hoạt động, nhưng nếu bạn làm điều tương tự trong trường hợp bạn có thể có nhiều hơn một hàng, bạn sẽ nhận được cùng một lỗi. Do đó, điều quan trọng là phải xem xét lý do tại sao ngoại lệ lại xảy ra.
Hãy kiểm tra mã của bạn:
while (myReader.Read())
{
info = myReader.GetString("info");
...
Cho đến nay rất tốt.
/**
* Write the relevant info in the LOGS
*/
connection.Close(); <---------- :S
connection.Open(); <---------- if I don´t do this I got some problems with the connection!!!!
Oh uh! Bạn đã khắc phục "một số vấn đề", nhưng bạn có biết những "vấn đề" đó là gì không? Nó thực sự ở đây mà bạn đã phá vỡ while
của bạn.
Tại điểm mà tôi đã nói "cho đến nay rất tốt", đây là những gì bạn đã xảy ra:
- Bạn có một đối tượng kết nối. Nó là "mở".
- Bạn có đối tượng trình đọc dữ liệu. Nó đang lấy dữ liệu từ kết nối.
Hiện tại, theo thông số IDbCommand.ExecuteReader
(http://msdn.microsoft.com/en-us/library/68etdec0.aspx), kết nối được sử dụng cho người đọc đó. Bạn không được phép làm bất cứ điều gì với kết nối đó ngoại trừ việc đóng nó, cho đến khi bạn gọi Close()
trên đầu đọc, hoặc rõ ràng hoặc thông qua Dispose()
như sẽ xảy ra nếu người đọc được chỉ định trong khối using
.
Hiện tại, điều này không phải lúc nào cũng đúng. Một thực hiện nhất định luôn được phép cung cấp cho bạn nhiều hơn một lời hứa giao diện (cho dù theo chữ ký giao diện hay theo tài liệu). Nhiều triển khai sẽ "giải phóng" kết nối để tái sử dụng khi Read()
trả về false (chỉ có một tôi đã thực hiện), SQLServer 2005 có một tùy chọn MultipleActiveResultSets=True
cho phép cùng một kết nối đồng thời hỗ trợ nhiều hơn một trình quản lý dữ liệu cùng một lúc (có những nhược điểm). Tuy nhiên, những nới lỏng của các quy tắc này sang một bên, điều duy nhất chúng tôi chắc chắn có thể làm với kết nối của chúng tôi ngay bây giờ, là gọi Close()
.
Vì lý do này, khi bạn cố gắng gọi cmdLog.ExecuteNonQuery()
bạn gặp "một số vấn đề" dưới dạng thông báo lỗi, vì bạn đang cố gắng sử dụng kết nối đang được sử dụng cho một thứ khác.
Vì vậy, bạn "cố định" điều này bằng cách làm điều duy nhất bạn có thể làm với kết nối - đóng nó - và sau đó mở lại. Đối với tất cả ý định và mục đích, bạn sẽ có một kết nối hoàn toàn mới!
Bây giờ, khi bạn lặp lại số while
, nó gọi lại là myReader.Read()
.Phương thức này đọc từ luồng dữ liệu đến từ kết nối và trả về false (nếu không có thêm kết quả) hoặc tạo một tập hợp các trường dựa trên những gì nó đọc từ luồng đó.
Nhưng không phải vì bạn đã đóng kết nối đó. Vì vậy, nó "phát nổ" với một ngoại lệ bởi vì bạn đang cố gắng đọc từ một kết nối khép kín và điều đó không thể thực hiện được.
Bây giờ, khi bạn thay thế while
này với một if
bạn không bao giờ trở lại hoạt động Read()
bạn muốn vỡ, vì vậy mã làm việc một lần nữa.
Nhưng bạn sẽ làm gì nếu bạn cần làm điều này với một kết quả có nhiều hàng?
Bạn có thể sử dụng MARS. Xem http://msdn.microsoft.com/en-us/library/h32h3abf%28v=vs.80%29.aspx cho điều đó. Thành thật mà nói tôi muốn tránh nó trừ khi cái gì đó tăng hơn thế này từ nó; nó có một số hàm ý tinh tế có thể gây nhầm lẫn nếu bạn đánh chúng.
Bạn có thể trì hoãn hoạt động tiếp theo của mình cho đến khi người đọc đóng cửa. Trong trường hợp này, điều này sẽ chỉ là một tiết kiệm nhỏ bằng cách bỏ đi không cần thiết Open()
và Close()
:
using(myReader = cmd.ExecuteReader())
{
while(myReader.Read())
{
string info = myReader.GetString("info");
/* Do stuff */
using(SqlConnection logConn = new SqlConnection(...))
{
logConn.Open();
string queryLog = "INSERT INTO ....;
MySqlCommand cmdLog = new MySqlCommand(queryLog, connection);
cmdLog.ExecuteNonQuery();
}
}
}
Bây giờ, nó có vẻ lãng phí để có hai kết nối chứ không phải ai ở đây. Tuy nhiên:
- Tạo kết nối tạo kết nối khá rẻ.
- Chúng tôi sẽ phát hành lại hồ bơi ngay khi chúng tôi thực hiện
ExecuteNonQuery()
, vì vậy nếu có rất nhiều điều này xảy ra trên nhiều chuỗi, tổng số kết nối khi di chuyển sẽ ít hơn gấp đôi số lượng chủ đề. Mặt khác, nếu chỉ có một chủ đề làm điều này, thì chỉ có một kết nối phụ, vì vậy ai quan tâm.
- Đóng kết nối khi nó là một phần thông qua việc cung cấp trình quản lý dữ liệu có thể đã làm sạch thêm trước khi quay lại hồ bơi, vì vậy bạn cũng có thể sử dụng hai kết nối (tôi không biết về SQLServer, nhưng tôi biết rằng một số cơ sở dữ liệu cần nhiều công việc hơn trước khi chúng có thể quay lại hồ bơi trong những trường hợp như vậy).
Tóm lại, bạn không thể sử dụng kết nối mà không sử dụng lại nó, đó là lỗi hết hạn. Bạn thường không thể có nhiều thao tác trên cùng một kết nối tại một thời điểm. Sử dụng tùy chọn MultipleActiveResultSets
với SQLServer2005 cho phép bạn làm điều đó, mặc dù nó có các biến chứng. Nói chung, nếu bạn muốn làm nhiều hơn một điều DB tại một thời điểm, bạn nên sử dụng nhiều hơn một kết nối.
Tất cả những gì đã nói, bạn vẫn có thể sử dụng if
hơn while
, nhưng làm điều đó bởi vì đó là những gì có ý nghĩa vào thời điểm đó, chứ không phải để sửa chữa một lỗi bạn không hiểu và có nó trở lại một thời gian khi if
isn không phải là một lựa chọn.
"Phát hiện" có nghĩa là gì? – SLaks
Dường như có một vấn đề cơ bản mà bạn có lẽ nên hiểu hơn là chỉ tránh nó như bạn có. Explode có nghĩa là gì? Là một ngoại lệ ném? Ngoại lệ là gì? –
Là một ngoại lệ-Tôi không có trong tay ngay bây giờ, nhưng là về các kết nối. Tôi đã chỉnh sửa bài đăng để thêm một số mã về nó. – Kani