System.Data.SqlClient.SqlCommand 有方法
BeginExecuteNonQuery
BeginExecuteReader
BeginExecuteXmlReader
和
EndExecuteNonQuery
EndExecuteReader
EndExecuteXmlReader
用于异步执行。
System.Data.IDbCommand 只有
ExecuteNonQuery
ExecuteReader
ExecuteXmlReader
仅用于同步操作。
是否有任何异步操作接口?
另外,为什么没有BeginExecuteScalar?
答案 0 :(得分:7)
我建议在使用数据库API时将DbCommand
及其朋友视为接口。为了在各种数据库提供者上推广API,DbCommand
实现与IDbCommand
一样好 - 或者可以说更好,因为它包含更新的技术,例如正确await
能{{} 1}} Task
成员。
MS无法向*Async()
添加任何具有新功能的新方法。如果他们要向IDbCommand
添加一个方法,那么这是一个重大变化,因为任何人都可以在他们的代码中自由地实现该接口,并且MS在框架中花了很多精力来保持ABI和API兼容性。如果他们在.net版本中扩展接口,之前工作的客户代码将停止编译,并且未重新编译的现有程序集将开始遇到运行时错误。此外,他们无法通过扩展方法添加适当的IDbCommand
或*Async()
方法,而无需在幕后对Begin*()
进行丑陋的投射(这本身就是一种不好的做法,打破了类型安全并且不必要地引入动态运行时强制转换)。
另一方面,MS可以在不破坏ABI的情况下向DbCommand
添加新的虚拟方法。向基类添加新方法可能会被视为破坏API(编译时,并不像运行时那样中断),因为如果您继承了DbCommand
并添加了一个具有相同名称的成员,那么您将开始获得警告CS0108: 'member1' hides inherited member 'member2'. Use the new keyword if hiding was intended.)。因此,DbCommand
可以获得新功能,对遵循良好实践的代码消耗影响最小(例如,大多数东西将继续工作,只要它不对类型系统起作用并使用{{{{{{ 1}})。
MS可能用来支持喜欢接口的人的一种可能的策略是引入名为DbCommand
的新接口,并myCommand.GetType().GetMethods()[3].Invoke(myCommand, …)
实现它们。他们没有这样做。我不知道为什么,但他们可能没有这样做,因为它会增加复杂性,直接消费IAsyncDbCommand
的替代方案为消费接口提供了大部分好处,但缺点很少。也就是说,它的回报很少。
答案 1 :(得分:3)
实际上,创建等同于BeginExecuteNonQuery,EndExecuteNonQuery等的异步行为将是相当困难的任务。这些API的实现远远优于简单生成单独的线程,等待数据库响应和调用回调。它们依赖于I / O重叠并提供更好的线程经济性。在网络跳跃,命令的数据库处理期间不会消耗额外的线程 - 这可能是在呼叫上花费的总时间的99%。对于几个调用它没有任何区别,但是当您设计高吞吐量服务器时,线程经济性变得非常重要。
我想知道为什么缺少BeginExecuteScalar。此外,大多数其他提供商(例如ODP.Net)根本没有异步API!
是的,没有异步操作的接口。
答案 2 :(得分:2)
为了解决这个问题,我构建了一个shim,如果它们存在于IDbConnection.IDbCommand / IDataReader上,则调用异步方法,如果不存在则调用常规方法。
来源: https://github.com/ttrider/IDbConnection-Async
的NuGet: https://www.nuget.org/packages/IDbConnection-Async/
示例:
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());
}
}
答案 3 :(得分:2)
IDbCommand
没有开始/结束异步方法,因为它们在ADO.NET的原始.NET 1.1版本中尚不存在,而当异步方法为added in .NET 2.0时,它本来就是将更改添加到IDbCommand
的重大更改(向接口添加成员是对该接口的实现者的重大更改)。
我不知道为什么BeginExecuteScalar
不存在,但它可以作为包裹BeginExecuteReader
的扩展方法实现。无论如何,在.NET 4.5中,我们现在有ExecuteScalarAsync
这样更容易使用。
答案 4 :(得分:1)
即使您正在检索“一个值”,大部分时间都将用于1)网络跳转到数据库服务器,2)数据库服务器执行命令。比你花费更多的时间来读取数据集中的1000条记录。所以,我同意,目前尚不清楚为什么没有BeginExecuteScalar ...
答案 5 :(得分:0)
您可以通过自定义代码实现异步行为,因为它不像您的问题那么复杂 - 您的目标没有任何标准的异步操作。
答案 6 :(得分:0)
当我需要将数据调用迁移到异步方法时,我偶然发现了这个问题。我为incorporate async interface创建了未来.NET Standard的问题。与此同时,我还创建了a library with a set of interfaces and adapters for System.Data。
答案 7 :(得分:-8)
没有它们的接口
没有BeginExecuteScalar
的原因是因为您可能不需要异步调用来获取单个值,这应该非常快