gpt4 book ai didi

c# - 在 ASP.NET Core 的存储库模式中使用接口(interface)和抽象类

转载 作者:太空宇宙 更新时间:2023-11-03 23:03:20 24 4
gpt4 key购买 nike

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

我对这段代码不满意。它太死板了,不能适应 future 。最重要的是,它没有编码为接口(interface),而是编码为实现。我提出了一个带有抽象类 Repository 的接口(interface) IRepository,它实现了所有辅助泛型方法。然后我创建了 BusinessRepository 来实现抽象的 Repository 类并调用通用的 helpers 方法。同样,我的同事告诉我删除 IRepository 接口(interface)并只使用 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);


}
}

最佳答案

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

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

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

您的 repo 层实际上应该只有您的 ConnectionManager 或通过 IoC 注入(inject)的连接工厂。

我们使用的技巧是在我们知道将成为存储过程参数(通常是大部分或全部)的数据模型字段上放置一个属性。然后我们有一个扩展方法,它反射(reflect)属性并提取字段、值和类型,创建一个小巧的 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 注入(inject)连接工厂。我认为您会发现关注点分离会大大简化事情。

关于c# - 在 ASP.NET Core 的存储库模式中使用接口(interface)和抽象类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42262427/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com