System.Data.IDbCommand и асинхронное выполнение? - PullRequest
10 голосов
/ 02 февраля 2012

System.Data.SqlClient.SqlCommand имеет методы

BeginExecuteNonQuery
BeginExecuteReader
BeginExecuteXmlReader

и

EndExecuteNonQuery
EndExecuteReader
EndExecuteXmlReader

для асинхронного выполнения.

System.Data.IDbCommand только имеет

ExecuteNonQuery
ExecuteReader
ExecuteXmlReader

, которые предназначены только для синхронных операций.

Есть ли интерфейс для асинхронных операций?
Кроме того, почему нет BeginExecuteScalar?

Ответы [ 8 ]

7 голосов
/ 14 февраля 2018

Я рекомендую обращаться с DbCommand и его друзьями, как если бы они были интерфейсами при использовании API баз данных.Ради обобщения API между различными поставщиками баз данных, DbCommand достигает так же хорошо, как и IDbCommand - или, возможно, лучше, потому что он включает в себя новые технологии, такие как надлежащие await способные Task *Async() члены.

MS не может добавлять новые методы с новыми функциями в IDbCommand.Если бы они добавили метод к IDbCommand, это было бы серьезным изменением, потому что любой может свободно реализовывать этот интерфейс в своем коде, а MS приложила немало усилий для сохранения совместимости ABI и API в рамках.Если бы они расширили интерфейсы в выпуске .net, код клиента, который ранее работал, прекратил бы компиляцию, и существующие сборки, которые не были перекомпилированы, начали бы сталкиваться с ошибками во время выполнения.Кроме того, они не могут добавлять надлежащие методы *Async() или Begin*() через методы расширения, не выполняя уродливое приведение к DbCommand за кулисами (что само по себе является плохой практикой, нарушая безопасность типов и излишне вводя динамическое приведение во время выполнения).

С другой стороны, MS может добавлять новые виртуальные методы в DbCommand, не нарушая ABI.Добавление новых методов в базовый класс может рассматриваться как нарушение API (время компиляции, не так плохо, как разрыв во время выполнения), потому что если вы унаследовали DbCommand и добавили элемент с тем же именем, вы начнете получать предупреждение CS0108: 'member1' скрывает унаследованный член 'member2'.Используйте новое ключевое слово, если скрытие было предназначено. ).Таким образом, DbCommand может получить новые функции с минимальным влиянием на потребление кода, что следует передовой практике (например, большинство вещей будет работать до тех пор, пока они не будут работать с системой типов и вызывать методы, использующие что-то вроде myCommand.GetType().GetMethods()[3].Invoke(myCommand, …)).

Возможной стратегией, которую MS могла бы использовать для поддержки людей, которым нравятся интерфейсы, было бы введение новых интерфейсов с именами, такими как IAsyncDbCommand, и DbCommand для их реализации.Они этого не сделали.Я не знаю почему, но они, вероятно, не сделали этого, потому что это увеличило бы сложность, и альтернатива непосредственного потребления DbCommand обеспечивает большую часть преимуществ для потребления интерфейсов с небольшим количеством недостатков.То есть это будет работать с небольшим возвратом.

3 голосов
/ 20 апреля 2012

На самом деле, создание асинхронного поведения, эквивалентного BeginExecuteNonQuery, EndExecuteNonQuery и т. Д., Было бы довольно сложной задачей. Реализация этих API намного превосходит простое создание отдельного потока, ожидание ответа базы данных и вызов обратного вызова. Они полагаются на перекрытие ввода-вывода и обеспечивают гораздо лучшую экономию потоков. Никакие дополнительные потоки не потребляются во время сетевого перехода, обработки базы данных команды - что, вероятно, составляет 99% от общего времени, затраченного на вызов. Для пары вызовов это не имеет значения, но при разработке высокопроизводительного сервера экономия потоков становится очень важной.

Мне было интересно, почему отсутствует BeginExecuteScalar. Кроме того, большинство других провайдеров, включая, например, ODP.Net, вообще не имеют асинхронного API!

И да, интерфейса для асинхронных операций нет.

2 голосов
/ 07 июля 2015

IDbCommand не имеет асинхронных методов начала / конца, потому что они еще не существовали в исходном выпуске ADO.NET .NET 1.1, и когда асинхронные методы были добавлены в .NET 2.0 было бы серьезным изменением добавить их в IDbCommand (добавление членов к интерфейсу является серьезным изменением для разработчиков этого интерфейса).

Я не знаю, почему BeginExecuteScalar не существует, но его можно реализовать как метод расширения, охватывающий BeginExecuteReader. В любом случае, в .NET 4.5 теперь есть ExecuteScalarAsync, который проще в использовании.

2 голосов
/ 11 июня 2015

Чтобы решить именно эту проблему, я создал оболочку, которая вызывает асинхронные методы, если они существуют в 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());
            }
        }
1 голос
/ 20 апреля 2012

Даже если вы извлекаете «одно значение», большая часть времени будет затрачена на 1) переход на сервер базы данных, 2) выполнение команды сервером базы данных.Намного больше времени, чем вы потратите, скажем, на чтение 1000 записей в наборе данных.Итак, я согласен, не понятно, почему нет BeginExecuteScalar ...

0 голосов
/ 02 июня 2017

Я наткнулся на этот вопрос, когда мне нужно перенести вызовы данных в асинхронные методы.Я создал проблему для будущего .NET Standard, чтобы включал асинхронный интерфейс .Тем временем я также создал библиотеку с набором интерфейсов и адаптеров для System.Data .

0 голосов
/ 02 февраля 2012

Вы можете реализовать асинхронное поведение с помощью своего пользовательского кода, поскольку он не так сложен, как по вашему вопросу - для ваших целей не существует стандартных асинхронных операций.

0 голосов
/ 02 февраля 2012

Нет, для них нет интерфейсов

Причина, по которой нет BeginExecuteScalar, заключается в том, что вам, вероятно, не понадобится асинхронный вызов для получения одного единственного значения, которое должно быть очень быстрым

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...