Создать асинхронную и синхронизированную версию методов Dapper без дублирования кода? - PullRequest
0 голосов
/ 27 мая 2019

Допустим, у меня есть простой класс, который содержит методы доступа к БД.Доступ к БД идет через Dapper.Какой самый простой способ создания асинхронных и синхронизированных версий этих методов без дублирования кода?Давайте возьмем в качестве примера 2 метода: GetUsers () и GetUsersAsync ().В этом случае оба метода будут иметь одинаковую логику.Единственное отличие состоит в том, что можно было бы вызвать sync и другую асинхронную версию метода Dapper, например, Query vs QueryAsync.

Просто вызвать GetUsersAsync (). Результат - плохая идея.Кто-нибудь решил эту проблему достаточно элегантно?

Ответы [ 2 ]

0 голосов
/ 27 мая 2019

Я сделал нечто похожее на вашу проблему, но с nHibernate.Проверьте это (часть моего файла):

Это наиболее важные функции, которые, к сожалению, должны как-то дублироваться.Эти функции делают весь повторяемый код.Параметр действия - это то, что им действительно нужно сделать (например, вставка). Контекст - это в основном сеанс nHibernate.В nHibernate каждая операция должна быть внутри сеанса.GetContextForStatement возвращает только новый сеанс или ранее открытый действительный.

    //sync version
    T GeneralExecuteAction<T>(Func<ISession, T> action)
    {
        lastDbError = DbError.Ok;
        using (var ctx = GetContextForStatement())
        {
            try
            {
                T result = action(ctx.session);
                ctx.CommitTransactionIfExists();
                return result;
            }
            catch (Exception ex)
            {
                ctx.RollbackTransactionIfExists();
                lastDbError = new DbError(ex);
                return default(T);
            }
        }
    }

    //async version 
    async Task<T> GeneralExecuteAction<T>(Func<ISession, Task<T>> action)
    {
        lastDbError = DbError.Ok;

        using (var ctx = GetContextForStatement())
        {
            try
            {
                T result = await action(ctx.session);
                await ctx.CommitTransactionIfExistsAsync();
                return result;
            }
            catch (Exception ex)
            {
                await ctx.RollbackTransactionIfExistsAsync();
                lastDbError = new DbError(ex);
                return default(T);
            }
        }
    }

Теперь вы можете просто использовать вышеуказанные функции в ваших публичных методах: Например, синхронизировать версию save:

    public DbError Save<T>(T obj) where T : class
    {
        GeneralExecuteAction((s) =>
        {
            s.Save(obj); //s is nHibernate session
            return true;
        });

        return lastDbError;
    }

Иасинхронная версия сохранения

    public async Task<DbError> SaveAsync<T>(T obj) where T : class
    {
        await GeneralExecuteAction((s) =>
        {
            s.Save(obj);
            return Task.FromResult(true);
        });

        return lastDbError;
    }
0 голосов
/ 27 мая 2019

Метод на уровне доступа к данным (DAL) не должен содержать намного больше логики, чем фактический запрос.Вы можете определить строку запроса и любые параметры как частные поля, к которым могут обращаться оба метода, например:

private const string ConnectionString = "...";
private const string Query = "SELECT Id, Name FROM Users";

public IEnumerable<User> GetUsers()
{
    using (var cn = new SqlConnection(ConnectionString))
        return cn.Query<SerieDailyValueDto>(Query).ToArray();
}

public Task<IEnumerable<User>> GetUsersAsync()
{
    using (var cn = new SqlConnection(ConnectionString))
        return await cn.QueryAsync<SerieDailyValueDto>(Query).ToArray();
}

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

...