15

System.Data.SqlClient.SqlCommand 有方法

BeginExecuteNonQuery
BeginExecuteReader
BeginExecuteXmlReader

EndExecuteNonQuery
EndExecuteReader
EndExecuteXmlReader

用于异步执行。

System.Data.IDbCommand 只有

ExecuteNonQuery
ExecuteReader
ExecuteXmlReader

仅用于同步操作。

有异步操作的接口吗?
另外,为什么没有 BeginExecuteScalar ?

4

8 回答 8

10

我建议DbCommand在使用数据库 API 时将其及其朋友视为接口。为了在各种数据库提供程序上通用 API,DbCommand实现的效果一样好——或者可以说更好IDbCommand,因为它包含了更新的技术,例如适当的成员。awaitTask *Async()

MS 无法将任何具有新功能的新方法添加到IDbCommand. 如果他们要IDbCommand在 . 如果他们在 .net 版本中扩展接口,以前工作的客户代码将停止编译,并且未重新编译的现有程序集将开始遇到运行时错误。此外,如果不对幕后进行丑陋的强制转换,他们就无法通过扩展方法添加适当的*Async()或方法(这本身就是一种不好的做法,破坏了类型安全并不必要地引入了动态运行时强制转换)。Begin*()DbCommand

另一方面,MS 可以在DbCommand不破坏 ABI 的情况下添加新的虚拟方法。向基类添加新方法可能会被视为破坏 API(编译时,不像运行时那样破坏),因为如果您继承DbCommand并添加了同名成员,您将开始收到警告CS0108: ' member1' 隐藏继承的成员 'member2'。如果打算隐藏,请使用 new 关键字。)。因此,DbCommand可以在对使用遵循良好实践的代码的影响最小的情况下获得新功能(例如,只要不违反类型系统并使用类似的方法调用方法,大多数东西都会继续工作myCommand.GetType().GetMethods()[3].Invoke(myCommand, …))。

MS 可以用来支持喜欢接口的人的一种可能策略是引入具有类似名称的新接口IAsyncDbCommandDbCommand实现它们。他们没有这样做。我不知道为什么,但他们可能没有这样做,因为这会增加复杂性,并且直接消费的替代方案为DbCommand消费接口提供了大部分好处,而几乎没有缺点。即,这将是几乎没有回报的工作。

于 2018-02-14T18:02:35.477 回答
3

实际上,创建等效于 BeginExecuteNonQuery、EndExecuteNonQuery 等的异步行为将是一项相当困难的任务。这些 API 的实现远远优于简单地产生一个单独的线程、等待数据库响应和调用回调。它们依赖于 I/O 重叠并提供更好的线程经济性。在网络跳跃、命令的数据库处理期间,没有消耗额外的线程——这可能是调用总时间的 99%。几次调用没有区别,但是当您设计高吞吐量服务器时,线程经济性变得非常重要。

我想知道为什么 BeginExecuteScalar 不见了。此外,大多数其他提供商,例如 ODP.Net,根本没有异步 API!

是的,没有用于异步操作的接口。

于 2012-04-20T04:38:44.707 回答
3

为了准确解决这个问题,我构建了一个 shim,如果 IDbConnection.IDbCommand/IDataReader 上存在异步方法,则调用它们,如果不存在,则调用常规方法。

来源: https ://github.com/ttider/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());
            }
        }
于 2015-06-10T22:32:10.367 回答
3

IDbCommand没有开始/结束异步方法,因为它们在 ADO.NET 的原始 .NET 1.1 版本中尚不存在,并且当在 .NET 2.0 中添加异步方法时,将它们添加到IDbCommand(将成员添加到接口是该接口的实现者的重大更改)。

我不知道为什么BeginExecuteScalar不存在,但它可以作为一个扩展方法来实现,环绕BeginExecuteReader. 无论如何,在 .NET 4.5 中,我们现在拥有ExecuteScalarAsync更易于使用的版本。

于 2015-07-06T22:33:12.543 回答
1

即使您正在检索“一个值”,大部分时间也会花在 1) 到数据库服务器的网络跃点上,2) 数据库服务器执行命令。比将 1000 条记录读入数据集所花费的时间要多得多。所以,我同意,不清楚为什么没有 BeginExecuteScalar ......

于 2012-04-20T04:46:53.973 回答
0

当我需要将数据调用迁移到异步方法时,我偶然发现了这个问题。我为未来的 .NET Standard 创建了一个问题,以合并 async interface。同时,我还为 System.Data 创建了一个包含一组接口和适配器的库

于 2017-06-01T21:39:51.630 回答
-1

您可以通过自定义代码实现异步行为,因为它并不复杂,就您的问题而言 - 没有任何标准的异步操作可以实现您的目标。

于 2012-02-02T12:04:04.027 回答
-10

不,它们没有接口

没有 a 的原因BeginExecuteScalar是因为您可能不需要异步调用来获取单个值,这应该非常快

于 2012-02-02T11:54:17.267 回答