dimanche 24 décembre 2017

C# Is this circular dependency, is a good design (Data Access Layer with Filter Provider)?

Hi I'm learning a lot about design patterns and SOLID Principles, but right now I need to apply that knowledge to an app.

I'm working on a data access layer, it has CRUD methods, but I need to APPLY FILTERS based on certain conditions before running those methods against the database and here is my design, I think I have a circular dependency, and wanted some guidance or help how to keep it SOLID.

Note: Filters need to be dinamically stored and loaded somehow from some storage.

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();
    }
  }

Note: I have a SetFiltersProvider in this abstract class because not every repository will apply filters, I think I need a Interface for that.

Everything works if I have a InMemoryFiltersProvider.

Trying to provide filters from Database I believe here I'm breaking SOLID Principles, because I depend from a BaseRepository implementation.

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;
    }
  }

Even when I'm working with interfaces I don't know if the Design it's clean, or circular dependecy problem.

Thanks so much.

Aucun commentaire:

Enregistrer un commentaire