2017-02-16 1 views
1

В настоящее время мы используем ORAP для доступа к данным путем вызова процедур хранения. Текущий код имеет класс BusinessFunctions, который наследует другой класс DataFunctions, который имеет вспомогательные методы для выполнения хранимых процедур.Использование интерфейса и абстрактного класса в шаблоне репозитория в ASP.NET Core

Я недоволен этим кодом. Это слишком жесткое, а не будущее доказательство. И, прежде всего, он не закодирован для интерфейса, довольно закодированного для реализации. Я предлагаю интерфейс IRepository с репозиторием абстрактного класса, который реализует все вспомогательные общие методы. Затем я создаю BusinessRepository, который реализует абстрактный класс репозитория и вызывает общий метод помощников. Опять же, мой коллега говорит мне удалить интерфейс IRepository и просто использовать абстрактный репозиторий.

public class BusinessFunctions : DataFunctions 
{ 
    public BusinessFunctions(ConnectionManager conMgr, LogWriter logWriter, AppUser appUser) : base(conMgr, logWriter, appUser) 
    { 

    } 

    public async Task<Business> FindAsync(int businessId) 
    { 
     throw new NotImplementedException(); 
    } 

    public async Task<Business> FindAsync(string businessGuid) 
    { 
     var lst = await StoredProcQueryAsync<Business>("spBusinessGetSetupGUID", new { BusinessGuid = businessGuid }); 

     if (lst.Count() == 0) 
      throw new NotFoundInDatabaseException("Business", businessGuid); 
     else 
      return lst.Single(); 
    } 

    public async Task<bool> IsHostedTokenizeCardAllowedAsync(string businessGuid) 
    { 
     var b = await FindAsync(businessGuid); 
     if (b.HostedPaymentEnabled) 
      return true; 
     else 
      return false; 
    } 
} 



public class DataFunctions : IDisposable 
{ 
    private ConnectionManager _conMgr; 
    private LogWriter _logWriter; 
    private AppUser _appUser; 

    public ConnectionManager ConnMgr 
    { 
     get { return _conMgr; } 
    } 

    protected LogWriter Logger 
    { 
     get { return _logWriter; } 
    } 

    protected AppUser User 
    { 
     get { return _appUser; } 
    } 

    public DataFunctions(ConnectionManager conMgr, LogWriter logWriter, AppUser appUser) 
    { 
     _conMgr = conMgr; 
     _logWriter = logWriter; 
     _appUser = appUser; 
    } 

    public void Dispose() 
    { 

    } 

    public async Task StoredProcExecuteNonQueryAsync(string storedProc, 
     List<StoredProcParameter> storedProcParameters = null, 
     SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default, 
     SqlAccessType accessType = SqlAccessType.ReadWrite 
     ) 
    { 
     using (SqlConnection conn = new SqlConnection(ConnMgr.SqlConnectionString)) 
     { 
      await conn.OpenAsync(); 
      await StoredProcExecuteNonQueryAsync(conn, 
       storedProc, 
       storedProcParameters: storedProcParameters, 
       commandTimeout: commandTimeout, 
       accessType: accessType); 
     } 
    } 

    public async Task StoredProcExecuteNonQueryAsync(SqlConnection conn, 
     string storedProc, 
     List<StoredProcParameter> storedProcParameters = null, 
     SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default, 
     SqlAccessType accessType = SqlAccessType.ReadWrite, 
     SqlTransaction trans = null 
     ) 
    { 
     using (SqlCommand cmd = new SqlCommand(storedProc, conn)) 
     { 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.CommandTimeout = (int)commandTimeout; 
      if (trans != null) cmd.Transaction = trans; 
      if (storedProcParameters != null) 
      { 
       foreach(var p in storedProcParameters) 
       { 
        cmd.Parameters.Add(p.ToSqlParameter()); 
       } 
      } 
      await cmd.ExecuteNonQueryAsync(); 
     } 
    } 

    public async Task<IEnumerable<T>> StoredProcQueryAsync<T>(string storedProc, 
     object storedProcParameters = null, 
     SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default, 
     SqlAccessType accessType = SqlAccessType.ReadWrite) 
    { 
     using (SqlConnection conn = new SqlConnection(ConnMgr.SqlConnectionString)) 
     { 
      conn.Open(); 
      return await StoredProcQueryAsync<T>(conn, 
       storedProc, 
       storedProcParameters, 
       commandTimeout); 
     } 
    } 

    public async Task<IEnumerable<T>> StoredProcQueryAsync<T>(SqlConnection conn, 
     string storedProc, 
     object storedProcParameters = null, 
     SqlCommandTimeout commandTimeout = SqlCommandTimeout.Default) 
    { 
     return await conn.QueryAsync<T>(storedProc, 
       commandType: CommandType.StoredProcedure, 
       commandTimeout: (int)commandTimeout, 
       param: storedProcParameters); 


    } 
} 

ответ

3

Я думаю, что причина вы несчастны с кодом является то, что он, кажется, смешиваясь функциональность сервиса в хранилище слоя. Уровень репозитория должен просто вызвать хранимую процедуру.

public async Task<bool> IsHostedTokenizeCardAllowedAsync(string businessGuid) 
{ 
    var b = await FindAsync(businessGuid); 
    if (b.HostedPaymentEnabled) 
     return true; 
    else 
     return false; 
} 

Это, к примеру, является хорошим кандидатом на сервисный уровень.

Ваш уровень репо должен быть просто подключен к вашему подключающему модулю или фабрике Connection через IoC.

Уловка, которую мы используем, заключается в том, чтобы поместить атрибут в поля модели данных, которые, как мы знаем, будут хранимыми процедурами (обычно большинство или все). Затем у нас есть метод расширения, который отражает атрибуты и вытягивает поля, значения и типы, создавая объект Dapper DynamicParameters. Большинство наших запросов на репозиторий выглядят так:

public async Task<User> AddUserAsync(UserAdd user) 
{ 
    using (var connection = _connectionFactory.Create() 
     { 
     var result = connection.ExecuteAsync("dbo.AddUser", user.GetParameters(), commandType: CommandType.StoredProcedure"; 
     return result; 
     } 
    } 

Это относительно быстрый и простой в использовании. Получает очень легко проверить. Вкладывает/удаляет/обновляет не так много. Вам нужно издеваться над SqlConnection, что может быть проблематичным.

Кроме того, если вы попадаете в более сложные области, которые могут быть изменены, вы можете использовать шаблон стратегии для перемещения методов в свои классы. Ниже будет приведен пример разделения ваш метод добавления в свой собственный класс:

public class MyRepository 
{ 
    private readonly IAddMethod<UserAdd> _addMethod; 
    private readonly IConnectionFactory _connectionFactory; 

    public MyRepository(IAddMethod<UserAdd> userAddMethod, 
     IConnectionFactory connectionFactory) 
    { 
     //..guard clauses, assignments, etc. 
    } 

    public async Task<int> AddAsync(UserAdd user) 
    { 
     return _addMethod.AddAsync(user); 
    } 
} 

Вы можете даже украсить эти методы стратегии в IoC, чтобы скрыть/увеличить их по мере необходимости. (в структуре структуры .DecorateAllWith()

Короче говоря, переместите любую логику на сервисный уровень, рассмотрите общий метод расширения для создания списка DynamicParameters и введите фабрику соединений через IoC. Я думаю, вы найдете разделение проблем значительно упростит ситуацию.

Смежные вопросы