Does Repository Pattern follow SOLID principles? Does Repository Pattern follow SOLID principles? asp.net asp.net

Does Repository Pattern follow SOLID principles?


Clearly it violates the single responsibility principle because when we implement this interface, In a single class we are putting Command and Query both. and this not expected.

That's not what Single Responsibility Principle means. SRP means that the class should have one primary concern. The primary concern of a repository is to "mediate between the domain and data mapping layers using a collection-like interface for accessing domain objects" (Fowler). That's what this class does.

Repository Pattern Breaks Interface segregation principle

If that bothers you, then simply provide another interface that doesn't include the method you're not going to implement. I personally wouldn't do that, though; it's a lot of extra interfaces for marginal benefit, and it clutters the API unnecessarily. A NotImplementedException is very self-explanatory.

You're going to find that there are a lot of rules, laws or principles in computing that have exceptions, and some that are outright wrong. Embrace the ambiguity, learn to write software from a more practical perspective, and stop thinking about software design in such absolute terms.


Clearly it violates the single responsibility principle

It's only clear if you have a very narrow definition of what the SRP is. The fact is SOLID violates SOLID. The principles themselves contradict themselves. SRP is at odds with DRY, since you often have to repeat yourself to properly separate concerns. LSP is at odds with ISP in some situations. OCP often conflicts with DRY and SRP. These principles are here not as hard and fast rules, but to guide you... try to adhere to them, but don't treat them as laws that cannot be broken.

On top of that, you are confusing the Repository architecture pattern, with a very specific Generic Repository implementation pattern. Note that a generic repository is different from a concrete repository. Nor is there any requirement that a Repository implement the methods you mention.

Yes, you can separate command and query as two separate concerns, but there is no requirement that you do so to make each a single responsibility. Command Query Seperation is a nice principle but not something that is covered by SOLID, and certainly there is no consensus on whether or not separating the concerns falls under the prevue of different responsibilities. They're more like different aspects of the same responsibility. You could take this to a ridiculous level if you wanted to and claim that Updating is a different responsibility from Deleting or that Querying by id is a different responsibility from querying by type or whatever. At some point you have to draw lines and box things in, and for most people "reading and writing an entity" is a single responsibility.

Repository Pattern Breaks Interface segregation principle

First, you are confusing Liskov Substitution Principal with Interface Segregation Principle. LSP is what is violated by your example.

As I said earlier, there is no requirement that Repository implement any specifc set of methods, other than a "collection-like interface". In fact, it would be perfectly acceptable to implement it like this:

public interface IRepository<T> where...[...] {IEnumerable<T> List { get; }}public interface CustRepository : IRepository<Customer>, IRepoAdd, IRepoUpdate, IRepoDelete, IRepoFind {}

Now it can optionally implement any of the other members without breaking LSP, although it's a rather silly implementation and one I certainly wouldn't implement just to avoid breaking LSP.

Fact is, there is probably no good reason why you would want a repository without delete. The only possible reason I can think of would be a Read-Only Repository, which I would define a separate interface for using a read-only collection interface.


I use the Repository pattern myself and I used the pattern to make sure all required interfaces are implemented. For this I created separate interfaces for all actions (IEntityCreator, IEntityReader, IEntityUpdater, IEntityRemover) and made the repostiory inherit all these interfaces. This way I can implement all methods in a concrete class and still use all interfaces separately. I don't see a reason to state that Repository pattern violates the SOLID principles. You just need to defined the 'responsibility' of the repository correctly: the responsibility of the Repository is to facilitate all access to the data of type T. That's all there is to say. As stated above I do also have a read-only repository interface named ReferenceRepository<T> which only includes the IEntityReader<T> interface. All interfaces are defined below for fast copying :) On top of that I also created a few concrete classes including the caching and/or logging. This is to incorporate any further actions required as stated by the I in SOLID. The type IEntity is used as a marker interface to allow only entities and not some other kind of object (you have to start somewhere).

/// <summary>/// This interface defines all properties and methods common to all Entity Creators./// </summary>/// <typeparam name="TEntity">The type of the entity.</typeparam>public interface IEntityCreator<TEntity>    where TEntity : IEntity{    #region Methods    /// <summary>    /// Create a new instance of <see cref="TEntity"/>    /// </summary>    /// <returns></returns>    TEntity Create();    #endregion}/// <summary>/// This interface defines all properties and methods common to all Entity Readers./// </summary>/// <typeparam name="TEntity">The type of the entity.</typeparam>public interface IEntityReader<TEntity>   where TEntity : IEntity{    #region Methods    /// <summary>    /// Get all entities in the data store.    /// </summary>    /// <returns></returns>    IEnumerable<TEntity> GetAll();    /// <summary>    /// Find all entities that match the expression    /// </summary>    /// <param name="whereExpression">exprssion used to filter the results.</param>    /// <returns></returns>    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereExpression);    #endregion}/// <summary>/// This interface defines all properties and methods common to all Entity Updaters. /// </summary>/// <typeparam name="TEntity">The type of the entity.</typeparam>public interface IEntityUpdater<TEntity>    where TEntity : IEntity{    #region Methods    /// <summary>    /// Save an entity in the data store    /// </summary>    /// <param name="entity">The entity to save</param>    void Save(TEntity entity);    #endregion}/// <summary>/// This interface defines all properties and methods common to all Entity removers./// </summary>/// <typeparam name="TEntity">The type of the entity.</typeparam>public interface IEntityRemover<TEntity>    where TEntity : IEntity{    /// <summary>    /// Delete an entity from the data store.    /// </summary>    /// <param name="entity">The entity to delete</param>    void Delete(TEntity entity);    /// <summary>    /// Deletes all entities that match the specified where expression.    /// </summary>    /// <param name="whereExpression">The where expression.</param>    void Delete(Expression<Func<TEntity, bool>> whereExpression);}/// <summary>/// This interface defines all properties and methods common to all Repositories./// </summary>public interface IRepository { }/// <summary>/// This interface defines all properties and methods common to all Read-Only repositories./// </summary>/// <typeparam name="TEntity">The type of the entity.</typeparam>public interface IReferenceRepository<TEntity> : IRepository, IEntityReader<TEntity>   where TEntity : IEntity{}/// <summary>/// This interface defines all properties and methods common to all Read-Write Repositories./// </summary>public interface IRepository<TEntity> : IReferenceRepository<TEntity>, IEntityCreator<TEntity>,    IEntityUpdater<TEntity>, IEntityRemover<TEntity>    where TEntity : IEntity{}