我一直在开发一个使用C#中的各种数据连接(例如数据库,rest api调用,json配置文件)的应用程序。我目前正在努力创建一个明智的数据访问层抽象,以便能够轻松地在这些之间进行切换。这些中的每一个都需要不同的连接设置,并且工作方式也不同。
我看了Repository模式的示例,但这并不完全适合我的需求。我希望能够定义一些查询模式,可以对其进行参数设置,并且该查询将能够处理参数。我目前拥有的示例:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
public class DatabaseQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string ConnectionString { get; set; }
public string CommandText { get; set; }
}
public class DatabaseConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : DatabaseQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var results = new List<TResult>();
using (var connection = new SqlConnection(query.ConnectionString))
using (var command = new SqlCommand(query.CommandText, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
results.Add(...
}
}
}
return results;
}
}
public class JsonQuery<TResult> : IQuery<IEnumerable<TResult>>
{
public string FileLocation { get; set; }
public Func<TResult, bool> Condition { get; set; }
}
public class JsonConnection<TQuery, TResult> : IQueryHandler<TQuery, IEnumerable<TResult>>
where TQuery : JsonQuery<TResult>
{
public IEnumerable<TResult> Handle(TQuery query)
{
var text = File.ReadAllText(query.FileLocation);
return Deserialize<TResult>(text).Results.Where(query.Condition);
}
}
public interface IQueryBuilder<TQuery, TParameters>
{
TQuery Build(TParameters parameters);
}
public class GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThan_DatabaseQueryBuilder :
IQueryBuilder<DatabaseQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public DatabaseQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new DatabaseQuery<Account>()
{
ConnectionString = "connString",
CommandText = $"SELECT * FROM Accounts WHERE Status = {parameters.Status} AND Balance = {parameters.Balance}"
};
}
}
public class GetAccountsByStatusAndBalanceHigherThan_JsonQueryBuilder
: IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
{
public JsonQuery<Account> Build(GetAccountsByStatusAndBalanceHigherThanQueryParameters parameters)
{
return new JsonQuery<Account>()
{
FileLocation = "fileLocation",
Condition = acc => acc.Status == parameters.Status && acc.Balance > parameters.Balance
};
}
}
public class GetAccountsByStatusAndBalanceHigherThanQuery : IQuery<IEnumerable<Account>>
{
public string Status { get; set; }
public decimal Balance { get; set; }
}
public class GetAccountsByStatusAndBalanceHigherThanQueryHandler :
IQueryHandler<GetAccountsByStatusAndBalanceHigherThanQuery, IEnumerable<Account>>
{
private readonly IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters>
_queryBuilder;
private readonly IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> _connection;
public GetAccountsByStatusAndBalanceHigherThanQueryHandler(
IQueryBuilder<JsonQuery<Account>, GetAccountsByStatusAndBalanceHigherThanQueryParameters> queryBuilder,
IQueryHandler<JsonQuery<Account>, IEnumerable<Account>> connection)
{
_queryBuilder = queryBuilder;
_connection = connection;
}
public IEnumerable<Account> Handle(GetAccountsByStatusAndBalanceHigherThanQuery query)
{
var jsonQuery = _queryBuilder.Build(new GetAccountsByStatusAndBalanceHigherThanQueryParameters
{
Status = query.Status,
Balance = query.Balance
});
return _connection.Handle(jsonQuery);
}
}
因此,有两个连接-一个数据库和一个Json文件连接。我已将连接的设置放入查询中,而数据库连接需要连接字符串和SQL命令,而Json连接则需要文件位置和对结果的一些过滤。问题出在最后一个查询处理程序中-GetAccountsByStatusAndBalanceHigherThanQueryHandler。我需要使它依赖于特定的连接,否则我无法编译它。我想要的是确保仅通过更改注入的参数就可以更改连接,并且所有连接都能正常工作。
请问您如何确保我可以轻松更改连接以及该体系结构是否很好吗?
答案 0 :(得分:0)
我认为您可能使这一过程复杂化了。在我看来,您有两个用于检索相同数据的数据源-一个是json数据源和一个数据库。这非常适合“一个接口,多个实现”领域。您还需要一个类来整理应使用的实现(这是工厂的完美用例)。您尝试传递到构造函数中的复杂查询逻辑,可以将其作为方法参数传递。
代码看起来像这样:
public interface IAccountDataAccess
{
IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance);
// etc.
}
public class JsonAccountDataAccess : IAccountDataAccess
{
private string jsonFilePath;
public JsonAccountDataAccess(string _jsonFilePath)
{
jsonFilePath = _jsonFilePath;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read json file, extract data, etc.
}
}
public class DatabaseAccountDataAccess : IAccountDataAccess
{
private string connectionString;
public DatabaseAccountDataAccess(string _connectionString)
{
connectionString = _connectionString;
}
public IEnumerable<Account> GetAccountsHigherThanBalance(Status status, Balance balance)
{
// read database, extract data, etc.
}
}
这是棘手的部分-您需要工厂在给出一些输入的情况下吐出正确的实现。我不确定您打算如何决定使用JSON还是数据库,但是假设您的客户端类知道:
public class AccountDataAccessFactory
{
public IAccountDataAccess GetDataAccess(bool useDatabase)
{
if(useDatabase) // you could use arbitrarily complex logic here
return new DatabaseAccountDataAccess(connString);
else
return new JsonAccountDataAccess(jsonFilePath);
}
}
您的客户端类可以这样使用它:
var factory = new AccountDataAccessFactory();
var dataAccess = factory.GetDataAccess(true);
var accounts = dataAccess.GetAccountsHigherThanBalance(status, balance);