Question

I need an advice on DDD (Domain Driven Design) and implementation of Repository pattern and encapsulation. To my understanding is that Repository pattern enables me to put all the database access logic in one place and abstract that logic from other parts of application. On the other side there is orm (Nhibernate, EntityFramework...) with its support for Linq and IQueryable. My toughts are: 1. If I am using repository then I should not use IQueryable as my return type bust instead use IEnumerable. Because if I use IQueryable then this would allow leaking database code to other application layers (IE would allow other devs to do queries in mvc controller where they don't belong). But every controls use IQueryable to access data and does this because is easier. If I use IQueryable as return type of my repository methods then: - I allow other developers to do database querying in other layers of application (and I think this should not be possible) - It will leak my domain entities (domain model) to other layers of applications (ie. User interface) but should not, instead DTO should be used.

My question is is IQueryable a good practice in DDD?

Was it helpful?

Solution

I would say it's not a good practice. Ideally you should have some sort of application layer on top of your domain. If you expose your domain objects directly or through Query object, someone might actually modify it outside of your control.

Personally i like to think of IQueryable as an implementation detail, ideally my domain would not depend on it (in case i want to switch my storage technology it could be a problem). Most often i'll end up using IQueryable internally inside my repositories implementation. What i usually end up with is implementing generic repository that has a FindBySpecification method, and then have specialized repositories for every Aggregate root that inherits from it. For example:

public interface IRepository<TEntity>        
{
    TEntity Get(Guid ID);
    void Add(TEntity entity);
    void Remove(TEntity entity);
    void Detach(TEntity entity);
    IEnumerable<TEntity> WithSpecification(ISpecification<TEntity> specification);
}

public interface IOrdersRepository : IRepository<Order>
{
    IEnumerable<Order> GetCompletedOrdersForAllPreferedCustomers(DateTime orderCompletedAfter);
    Order GetOrderBySomeOtherComplicatedMeans();
}

Another aproach is to design your application to follow the CQRS principle. Then you can have your DomainModel doing it's magic on the command side, and create a readonly model of your data for your client on the query side. This setup can become really elaborate depending on your requirements, but it can be as simple as two ORM models mapped to the same database (the one on the command side is mapping your domain entities, the one on the query sides maps to simple DTOs ).

OTHER TIPS

Personally I do not feel that exposing EF entities by way of IQueryable across all layers is necessarily a bad thing. But this is just my own opinion. Others may not agree especially if you look at it on the encapsulation perspective. But generally the concept of loose-coupling is a trade-off between complexity and practical gain. By encapsulating IQueryable know that you will loose a lot of practical gain, like the ability to lazy-load for instance.

If your application layer is directly on top of your repository layer, I vote to use IEnnumerable instead of IQueryable. But if you have a service layer in the middle (which I personally prefer to contain all business logic so the repository layer can specialize with data access operations) then I will have the repository return IQueryable and have the service layer return IEnnumerable after it has performed its business logic from the IQueryable object returned by the repository.

These are just my own personal rules:

  1. If you need to encapsulate EF, encapsulate it away only from the application layer. Otherwise, use it as excessively as you need on all layers. EF is very powerful, encapsulating it in the repository layer will make you lose a lot of its power
  2. The application layer should be as thin as possible, it should not perform any further processing on the data it receives from the layer below it. It receives the list and it renders it, that's it.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top