2011-10-20 22 views
51

Trong khi sử dụng sử dụng() {} (sic) khối như hình dưới đây, và giả định rằng cmd1 không sống vượt ra ngoài phạm vi của đầu tiên sử dụng() {} khối, tại sao nên ném khối thứ hai một ngoại lệ với thông báo SqlParameter đã được chứa bởi một SqlParameterCollection khác? Điều đó có nghĩa là tài nguyên và/hoặc xử lý - bao gồm các tham số (SqlParameterCollection) - đính kèm với cmd1 không được giải phóng khi bị phá hủy ở cuối khối không?SqlParameter đã được chứa bởi một SqlParameterCollection khác - Có sử dụng() {} cheat?

using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Test;Integrated Security=True")) 
{ 
    var parameters = new SqlParameter[] { new SqlParameter("@ProductId", SqlDbType.Int) }; 

    using(var cmd1 = new SqlCommand("SELECT ProductName FROM Products WHERE ProductId = @ProductId")) 
    { 
     foreach (var parameter in parameters) 
     { 
      cmd1.Parameters.Add(parameter);     
     } 
     // cmd1.Parameters.Clear(); // uncomment to save your skin! 
    } 

    using (var cmd2 = new SqlCommand("SELECT Review FROM ProductReviews WHERE ProductId = @ProductId")) 
    { 
     foreach (var parameter in parameters) 
     { 
      cmd2.Parameters.Add(parameter); 
     } 
    } 
} 

LƯU Ý: Làm cmd1.Parameters.Clear() ngay trước khi cú đúp cuối cùng của đầu tiên sử dụng() {} khối sẽ giúp bạn tiết kiệm từ ngoại lệ (và có thể xấu hổ).

Nếu bạn cần để tái tạo, bạn có thể sử dụng các kịch bản sau đây để tạo ra các đối tượng:

CREATE TABLE Products(
    ProductId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, 
    ProductName nvarchar(32) NOT NULL) 
GO 

CREATE TABLE ProductReviews(
    ReviewId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, 
    ProductId int NOT NULL, 
    Review nvarchar(128) NOT NULL) 

GO 

Trả lời

66

Tôi nghi ngờ rằng SqlParameter "biết" mà lệnh đó là một phần của, và rằng thông tin đó không được xóa khi lệnh được xử lý, nhưng bị xóa khi bạn gọi command.Parameters.Clear().

Cá nhân tôi nghĩ rằng tôi muốn tránh tái sử dụng các đối tượng ở nơi đầu tiên, nhưng đó là tùy thuộc vào bạn :)

+0

Cảm ơn. Tôi nghi ngờ đó là trường hợp. Nó cũng có nghĩa là SqlParameter kết hợp chính nó với một đối tượng đã được xử lý mà tôi không chắc chắn một điều tốt của nó là –

+0

@JohnGathogo: Vâng, nó liên kết với một đối tượng được xử lý * sau * liên kết đã được hình thành. Nó không phải là lý tưởng, chắc chắn. –

+4

Một lưu ý cho người khác. Tôi phải thực hiện 'Clear' trước khi thoát khỏi khối' using' đầu tiên. Làm điều đó khi vào khối 'using' thứ 2 của tôi vẫn còn ném lỗi này. – Snekse

6

Sử dụng khối không đảm bảo rằng một đối tượng được "tiêu diệt", chỉ đơn giản là phương pháp được gọi là Dispose() . Những gì thực sự làm là tùy thuộc vào việc thực hiện cụ thể và trong trường hợp này rõ ràng là không làm trống bộ sưu tập. Ý tưởng là để đảm bảo rằng các tài nguyên không được quản lý sẽ không được dọn dẹp bởi bộ thu gom rác được xử lý một cách chính xác. Vì bộ sưu tập Tham số không phải là một tài nguyên không được quản lý nên nó không hoàn toàn đáng ngạc nhiên vì nó không được xóa bởi phương thức vứt bỏ.

2

using xác định phạm vi và thực hiện cuộc gọi tự động Dispose() mà chúng tôi yêu thích.

Tham chiếu nằm ngoài phạm vi sẽ không làm cho đối tượng trở thành "biến mất" nếu đối tượng khác có tham chiếu đến nó, trong trường hợp này là parameters có tham chiếu đến cmd1.

2

Thêm cmd.Parameters.Clear(); sau khi thực hiện nên được tốt.

0

Tôi gặp phải ngoại lệ này vì tôi không thể khởi tạo đối tượng tham số. Tôi nghĩ rằng nó đã phàn nàn về hai thủ tục có các tham số có cùng tên. Nó đã phàn nàn về cùng một tham số được thêm hai lần.

  Dim aParm As New SqlParameter() 
      aParm.ParameterName = "NAR_ID" : aParm.Value = hfCurrentNAR_ID.Value 
      m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) 
      aParm = New SqlParameter 
      Dim tbxDriveFile As TextBox = gvNetworkFileAccess.Rows(index).FindControl("tbxDriveFolderFile") 
      aParm.ParameterName = "DriveFolderFile" : aParm.Value = tbxDriveFile.Text 
      m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) 
      **aParm = New SqlParameter()** <--This line was missing. 
      Dim aDDL As DropDownList = gvNetworkFileAccess.Rows(index).FindControl("ddlFileAccess") 
      aParm.ParameterName = "AccessGranted" : aParm.Value = aDDL.Text 
      **m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm)** <-- The error occurred here. 
Các vấn đề liên quan