2017-02-16 58 views
1

我们正在使用dapper ORM通过调用存储过程来访问数据。当前代码有一个BusinessFunctions类,该类继承另一个具有辅助方法来执行存储过程的DataFunctions类。在ASP.NET Core中使用存储库模式中的接口和抽象类

我对此代码不满意。这太僵硬了,没有前途证明。最重要的是,它不是编码到接口而是编码到实现。我提出了一个接口IRepository和一个抽象类Repository,它实现了所有的Helper泛型方法。然后创建实现抽象Repository类的BusinessRepository并调用泛型助手方法。同样,我的同事告诉我要删除IRepository接口,并使用Repository抽象类。

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; 
} 

例如,这是一个很好的候选人在服务层。

您的回购层应该只有您的ConnectionManager或通过IoC注入的连接工厂。

我们使用的技巧是在数据模型字段上放置一个属性,我们知道它将存储过程参数(通常是大部分或全部)。然后我们有一个扩展方法,它反映了这些属性,并提取了创建精细的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。另外,如果您进入更复杂的领域并可能发生变化,您可以使用战略模式将方法移动到他们自己的类中。下面是分裂的add方法变成自己的类的例子:

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); 
    } 
} 

你甚至可以装饰在国际奥委会,这些策略的方法来隐藏/根据需要增加它们。 (在结构地图中是.DecorateAllWith()

简而言之,将任何逻辑移动到服务层,考虑创建DynamicParameters列表的通用扩展方法,并通过IoC注入连接工厂。我想你会发现分离的担忧会使事情显着地变得简单化