您好我很多关于设计模式和SOLID原则的学习,但是现在我需要将这些知识应用到应用程序中。
我正在处理数据访问层,它有CRUD方法,但我需要在针对数据库运行这些方法之前根据某些条件应用FILTERS,这是我的设计,我想我有一个循环依赖,并希望得到一些指导或帮助如何保持它。
注意:过滤器需要以某种方式以某种方式存储和加载。
IRepository.cs
public interface IRepository<TEntity>
where TEntity : IEntity
{
void Add(TEntity entity);
TEntity Get(int id);
//more actions ....
}
IFiltersProvider.cs
public interface IFiltersProvider
{
IQueryable<TEntity> ApplyFilters<TEntity>(IQueryable<TEntity> query)
where TEntity : IEntity;
}
BaseRepository.cs
public abstract class BaseRepository<TEntity> : IRepository<TEntity>
where TEntity : IEntity
{
protected IFiltersProvider filtersProvider;
public void SetFiltersProvider(IFiltersProvider filtersProvider)
{
this.filtersProvider = filtersProvider;
}
public void Add(TEntity entity)
{
// Add to database without filters ....
}
public TEntity Get(int id)
{
var query = ;//get here a IQueryable;
filtersProvider?.ApplyFilters(query);
return query.FirstOrDefault();
}
}
注意:我在这个抽象类中有一个 SetFiltersProvider ,因为不是每个存储库都会应用过滤器,我想我需要一个接口。
如果我有InMemoryFiltersProvider,那么一切正常。
尝试从数据库提供过滤器我相信这里我打破了SOLID原则,因为我依赖于BaseRepository实现。
FilterRepository.cs
public class FilterRepository : BaseRepository<Filter>, IRepository<Filter>
{
}
DBFiltersProvider.cs
public class DBFiltersProvider: IFiltersProvider
{
protected readonly FilterRepository filterRepository;
public DBFiltersProvider(FilterRepository filterRepository)
{
filterRepository.SetFiltersProvider(this);
this.filterRepository = filterRepository;
}
public IQueryable<TEntity> ApplyFilters<TEntity>(IQueryable<TEntity> query)
where TEntity : IEntity
{
var filters = filterRepository.GetFiltersByEntity<TEntity>();
foreach (var filter in filters)
{
// logic to apply filter to query
}
return query;
}
}
即使我使用界面,我也不知道设计是干净还是循环依赖问题。
非常感谢。
答案 0 :(得分:0)
几年前我遇到过类似的问题。我更喜欢使用postsharp的拦截功能来应用装饰器模式。
这样你应该将调用重定向到具有filter参数的方法,然后拦截器能够在将其传递给原始方法体之前修改过滤器。
它是声明性的,因此您只能将拦截应用于所需的存储库;所以没有预期的循环依赖。
答案 1 :(得分:0)
您遇到了通用存储库的常见问题。我称之为漏洞抽象,因为存储库的消费者需要对数据层的深入了解才能使用过滤。通用存储库并不总是最好的解决方案。考虑实现非常具体的搜索功能,具体取决于您真正需要的内容.FindOrdersForAccount。或者,如果您仍然需要更多的灵活性,可以使用自己的输入和输出模型单独使用IqueryService。我的观点是,对于一些简单的CRUD工作,通用存储库是上帝,对于您希望在代码中更具表现力的更高级用例。