2012-02-02 39 views
6

System.Data.SqlClient.SqlCommand có phương phápSystem.Data.IDbCommand và thực thi không đồng bộ?

BeginExecuteNonQuery 
BeginExecuteReader 
BeginExecuteXmlReader 

EndExecuteNonQuery 
EndExecuteReader 
EndExecuteXmlReader 

để thực hiện đồng bộ.

System.Data.IDbCommand chỉ có

ExecuteNonQuery 
ExecuteReader 
ExecuteXmlReader 

mà là dành cho chỉ hoạt động đồng bộ.

Có giao diện nào cho các hoạt động không đồng bộ không?
Ngoài ra, tại sao không có BeginExecuteScalar?

Trả lời

1

IDbCommand không có bắt đầu/phương pháp cuối async vì họ vẫn chưa tồn tại trong bản gốc NET 1.1 phát hành ADO.NET, và khi các phương pháp async là added in .NET 2.0 nó sẽ là một thay đổi đột phá để thêm những người vào IDbCommand (thêm thành viên vào một giao diện là một thay đổi phá vỡ cho những người triển khai giao diện đó).

Tôi không biết tại sao BeginExecuteScalar không tồn tại, nhưng nó có thể được triển khai như một phương pháp mở rộng kết thúc tốt đẹp quanh BeginExecuteReader. Dù sao trong .NET 4.5, chúng tôi hiện có ExecuteScalarAsync dễ sử dụng hơn.

+0

Tôi không thấy 'IDbCommand.ExecuteScalarAsync()'. Những gì [tài liệu] (https://msdn.microsoft.com/en-us/library/system.data.idbcommand (v = vs.110) .aspx) bạn đang xem? – binki

+3

Ồ, bạn đang nói ['SqlCommand.ExecuteScalarAsync()'] (https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalarasync%28v=vs.110%29. aspx). Tôi hiểu rồi. – binki

+1

@binki hoặc ['DbCommand.ExecuteScalarAsync()'] (https://msdn.microsoft.com/en-us/library/hh223677 (v = vs.110) .aspx), không hoàn toàn tốt bằng có nó trên giao diện, nhưng không hỗ trợ một số đa hình. – phoog

-5

Không không có giao diện cho họ

Lý do tại sao không có một BeginExecuteScalar là bởi vì có thể bạn sẽ không cần một cuộc gọi async để có được một giá trị duy nhất trở lại mà nên rất nhanh chóng

+7

Đó là "một giá trị" có thể liên quan đến 50 bảng, một vài chế độ xem, có thể là một số procs được lưu trữ v.v. Đó không phải là lý do :) – Onkelborg

+0

Đó là lý do duy nhất tôi có thể tự cung cấp cho mình resealable..If để nhận được một giá trị form db của bạn, bạn cần phải liên quan đến 50 bảng có cái gì đó sai với lược đồ của bạn và một cuộc gọi async sẽ không giúp :-) –

+0

@Massimiliano Peluso: Cấp 95% các trường hợp bạn nói đúng. Nhưng nếu bạn có một lược đồ như vậy, không có cách nào để thay đổi nó trong một thông báo ngắn, điều này chỉ làm tăng sự cần thiết cho một phương thức không đồng bộ. –

0

Bạn có thể thực hiện hành vi không đồng bộ bằng mã tùy chỉnh của bạn, vì nó không quá phức tạp, như đối với câu hỏi của bạn - không có bất kỳ hoạt động không đồng bộ chuẩn nào cho mục tiêu của bạn.

3

Thực ra, việc tạo hành vi không đồng bộ tương đương với BeginExecuteNonQuery, EndExecuteNonQuery, v.v. sẽ là một nhiệm vụ khá khó khăn. Việc triển khai các API này vượt trội hơn nhiều so với việc tạo ra một luồng riêng biệt đơn giản, chờ đợi phản hồi của cơ sở dữ liệu và gọi lại gọi lại. Họ dựa vào sự chồng chéo I/O và cung cấp nền kinh tế chủ đề tốt hơn nhiều. Không có chủ đề bổ sung nào được tiêu thụ trong suốt thời gian hop mạng, xử lý cơ sở dữ liệu của lệnh - có lẽ là 99% tổng thời gian dành cho cuộc gọi. Đối với một vài cuộc gọi nó làm cho không có sự khác biệt, nhưng khi bạn thiết kế một máy chủ thông lượng cao, nền kinh tế thread trở nên rất quan trọng.

Tôi đã tự hỏi tại sao BeginExecuteScalar bị thiếu. Ngoài ra, hầu hết các nhà cung cấp khác, bao gồm ODP.Net chẳng hạn, không có API async nào cả!

Và có, không có giao diện cho các hoạt động không đồng bộ.

1

Ngay cả khi bạn đang truy xuất "một giá trị" phần lớn thời gian sẽ được chi tiêu trên 1) mạng hop đến máy chủ cơ sở dữ liệu, 2) lệnh thực thi máy chủ cơ sở dữ liệu. Nhiều thời gian hơn bạn sẽ chi tiêu vào nói đọc 1000 hồ sơ vào tập dữ liệu. Vì vậy, tôi đồng ý, không rõ tại sao không có BeginExecuteScalar ...

2

Để giải quyết chính xác vấn đề này, tôi đã tạo một shim gọi các phương thức không đồng bộ nếu chúng tồn tại trên IDbConnection.IDbCommand/IDataReader hoặc gọi các phương thức thông thường nếu chúng không t.

Nguồn: https://github.com/ttrider/IDbConnection-Async

NuGet: https://www.nuget.org/packages/IDbConnection-Async/

Ví dụ:

 using (IDbConnection connection = new SqlConnection(connectionString)) 
     { 
      await connection.OpenAsync(); 

      IDbCommand command = connection.CreateCommand(); 
      command.CommandText = "SELECT Name FROM Person;"; 
      using (IDataReader reader = await command.ExecuteReaderAsync()) 
      { 
       do 
       { 
        while (await reader.ReadAsync()) 
        { 
         if (!await reader.IsDBNullAsync(0)) 
         { 
          var name = reader.GetFieldValueAsync<string>(0); 
          Assert.IsNotNull(name); 
         } 
        } 
       } while (await reader.NextResultAsync()); 
      } 
     } 
1

Tôi khuyên bạn nên xử lý DbCommand và bạn bè của mình như thể chúng là giao diện khi sử dụng API cơ sở dữ liệu. Vì mục đích khái quát hóa API trên các nhà cung cấp cơ sở dữ liệu khác nhau, DbCommand đạt được cũng như IDbCommand —hoặc, được cho là tốt hơn, bởi vì nó bao gồm các công nghệ mới hơn như await có thể Task*Async() thành viên.

MS không thể thêm bất kỳ phương pháp mới nào có chức năng mới vào IDbCommand. Nếu họ thêm phương thức vào IDbCommand, đó là một thay đổi đột phá bởi vì bất kỳ ai được tự do triển khai giao diện đó trong mã của họ và MS đã nỗ lực nhiều trong việc bảo toàn khả năng tương thích ABI và API trong khuôn khổ. Nếu họ mở rộng giao diện trong một bản phát hành của .net, mã khách hàng mà trước đây đã làm việc sẽ ngừng biên dịch và hội đồng hiện có mà không được biên dịch lại sẽ bắt đầu gặp phải lỗi thời gian chạy. Ngoài ra, họ không thể thêm các phương thức thích hợp *Async() hoặc Begin*() thông qua các phương pháp tiện ích mà không làm xấu đúc đến DbCommand phía sau hậu trường (chính là hành vi xấu, phá vỡ an toàn loại và giới thiệu thời gian chạy động không cần thiết).

Mặt khác, MS có thể thêm các phương thức ảo mới vào DbCommand mà không vi phạm ABI. Việc thêm các phương thức mới vào một lớp cơ sở có thể được coi là phá vỡ API (thời gian biên dịch, không phải là xấu để phá vỡ thời gian chạy) vì nếu bạn thừa kế DbCommand và đã thêm một thành viên có cùng tên, bạn sẽ bắt đầu nhận được cảnh báo CS0108: 'member1' hides inherited member 'member2'. Use the new keyword if hiding was intended.) . Do đó, DbCommand có thể nhận các tính năng mới với tác động tối thiểu đến mã tiêu thụ tuân theo các phương pháp hay (ví dụ: hầu hết mọi thứ sẽ tiếp tục hoạt động miễn là nó không hoạt động với hệ thống kiểu và phương thức gọi bằng cách sử dụng một cái gì đó như myCommand.GetType().GetMethods()[3].Invoke(myCommand, …)).

Một chiến lược có thể mà MS có thể đã sử dụng để hỗ trợ những người thích giao diện sẽ giới thiệu giao diện mới với các tên như IAsyncDbCommand và có DbCommand triển khai chúng. Họ đã không làm điều này. Tôi không biết tại sao, nhưng họ có thể không làm điều này bởi vì nó sẽ làm tăng sự phức tạp và thay thế trực tiếp tiêu thụ DbCommand cung cấp hầu hết các lợi ích cho việc tiêu thụ giao diện với một vài nhược điểm. Tức là, nó sẽ hoạt động với một chút trở lại.

Các vấn đề liên quan