C#这是循环依赖,是一个很好的设计(带过滤器的数据访问层)?

时间:2017-12-24 13:47:07

标签: c# database design-patterns database-design entity-framework-core

您好我很多关于设计模式和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;
    }
  }

即使我使用界面,我也不知道设计是干净还是循环依赖问题。

非常感谢。

2 个答案:

答案 0 :(得分:0)

几年前我遇到过类似的问题。我更喜欢使用postsharp的拦截功能来应用装饰器模式。

这样你应该将调用重定向到具有filter参数的方法,然后拦截器能够在将其传递给原始方法体之前修改过滤器。

它是声明性的,因此您只能将拦截应用于所需的存储库;所以没有预期的循环依赖。

答案 1 :(得分:0)

您遇到了通用存储库的常见问题。我称之为漏洞抽象,因为存储库的消费者需要对数据层的深入了解才能使用过滤。通用存储库并不总是最好的解决方案。考虑实现非常具体的搜索功能,具体取决于您真正需要的内容.FindOrdersForAccount。或者,如果您仍然需要更多的灵活性,可以使用自己的输入和输出模型单独使用IqueryService。我的观点是,对于一些简单的CRUD工作,通用存储库是上帝,对于您希望在代码中更具表现力的更高级用例。