【问题标题】:Using interface and abstract class in repository pattern in ASP.NET Core在 ASP.NET Core 的存储库模式中使用接口和抽象类
【发布时间】:2017-02-16 00:04:33
【问题描述】:

我们目前正在使用 dapper ORM 通过调用存储过程来访问数据。当前代码有一个类 BusinessFunctions,它继承了另一个类 DataFunctions,后者有辅助方法来执行存储过程。

我对这段代码不满意。它太死板了,没有未来的证明。最重要的是,它没有编码为接口,而是编码为实现。我提出了一个带有抽象类 Repository 的接口 IRepository,它实现了所有辅助泛型方法。然后我创建实现抽象 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);


    }
}

【问题讨论】:

    标签: c# asp.net generics


    【解决方案1】:

    我认为您对代码不满意的原因是它似乎将服务功能混合到存储库层中。存储库层应该简单地调用存储过程。

    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 中修饰这些策略方法以根据需要隐藏/增强它们。 (在结构图中是 .DecorateAllWith()

    简而言之,将任何逻辑移至服务层,考虑创建 DynamicParameters 列表的通用扩展方法,并通过 IoC 注入连接工厂。我想你会发现关注点分离会大大简化事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-10
      • 1970-01-01
      相关资源
      最近更新 更多