2017-02-16 18 views
1

現在、ストアプロシージャを呼び出すことによってデータにアクセスするために、DApper ORMを使用しています。現在のコードは、ストアドプロシージャを実行するヘルパーメソッドを持つ別のクラスのDataFunctionsを継承するクラスBusinessFunctionsを持っています。ASP.NETコアのリポジトリパターンでインターフェイスと抽象クラスを使用する

私はこのコードに満足できません。それはあまりにも硬く、将来の証拠ではありません。そして、とりわけ実装にコード化されているのではなく、インタフェースにコード化されていません。私はすべてのヘルパージェネリックメソッドを実装する抽象クラスリポジトリを持つインタフェースIRepositoryを提案します。次に、抽象リポジトリクラスを実装し、ジェネリックヘルパーメソッドを呼び出す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; 
} 

これは、たとえば、サービス層に入れるのに適した候補です。

あなたのRepoレイヤーは実際にはIoC経由でConnectionManagerまたはConnectionファクトリを注入するだけです。

私たちが使用するトリックは、ストアドプロシージャのパラメータ(通常はほとんどまたはすべて)になることがわかっているデータモデルフィールドに属性を設定することです。次に、属性を反映し、フィールド、値、およびタイプを引き出して、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); 
    } 
} 

あなたも、必要に応じてそれらを強化/非表示にするのIoCでこれらの戦略法を飾ることができます。 (構造マップで)

要するに、ロジックをサービスレイヤーに移動し、DynamicParametersリストを作成する一般的な拡張メソッドを検討し、IoC経由で接続ファクトリを挿入します。懸念事項が大幅に簡素化されます。

関連する問題