Variations of the Repository Pattern I've been using this variation of the Repository pattern for over a year now:

 public interface IReadOnlyRepository&lt;T, in TId&gt;
     where T : AbstractEntity&lt;TId&gt;
    {
        T Get( TId id );
        IEnumerable&lt;T&gt; GetAll();
    }

/// &lt;summary&gt;
/// Defines a generic repository interface for
/// classes solely in charge of getting and processing data from a data source
/// &lt;/summary&gt;
/// &lt;typeparam name="T"&gt;&lt;/typeparam&gt;
/// &lt;typeparam name="TId"&gt;The type of the id.&lt;/typeparam&gt;
public interface IRepository&lt;T, in TId&gt; : IReadOnlyRepository&lt;T, TId&gt; where T : AbstractEntity&lt;TId&gt;
{
    /// &lt;summary&gt;
    /// Determines whether the specified entity has duplicates.
    /// &lt;/summary&gt;
    /// &lt;param name="entity"&gt;The entity.&lt;/param&gt;
    /// &lt;returns&gt;
    ///   &lt;c&gt;true&lt;/c&gt; if the specified entity has duplicates; otherwise, &lt;c&gt;false&lt;/c&gt;.
    /// &lt;/returns&gt;
    bool HasDuplicates(T entity);

    /// &lt;summary&gt;
    /// Inserts the specified entity.
    /// &lt;/summary&gt;
    /// &lt;param name="entity"&gt;The entity.&lt;/param&gt;
    void Save( T entity );
    /// &lt;summary&gt;
    /// Inserts the entity or updates it if it already exists.
    /// &lt;/summary&gt;
    /// &lt;param name="entity"&gt;The entity.&lt;/param&gt;
    T SaveOrUpdate( T entity );

    /// &lt;summary&gt;
    /// Updates the specified entity.
    /// &lt;/summary&gt;
    /// &lt;param name="entity"&gt;The entity.&lt;/param&gt;
    /// &lt;returns&gt;&lt;/returns&gt;
    T Update(T entity);

    /// &lt;summary&gt;
    /// Deletes the specified entity from the data source.
    /// &lt;/summary&gt;
    /// &lt;param name="entity"&gt;The entity.&lt;/param&gt;
    void Delete(T entity);

    /// &lt;summary&gt;
    /// Deletes the entity with the specified id.
    /// &lt;/summary&gt;
    /// &lt;param name="id"&gt;The id.&lt;/param&gt;
    void Delete(TId id);
}


but recently, after rereading some books on Design Patterns, I've had this seemingly amazing idea to apply some patterns to my repositories.

public interface IRepository&lt;T, in TId&gt; : IReadOnlyRepository&lt;T, TId&gt; where T : AbstractEntity&lt;TId&gt;
{
    void Execute(IRepositoryCommand command);
    void Execute(IBatchRepositoryCommand command);
}

public interface IRepositoryCommand&lt;T&gt;
{
    void Execute(T entity);
}

public interface IBatchRepositoryCommand&lt;T&gt;
{
    void Execute(IEnumerable&lt;T&gt; entities);
}

public SaveCommand&lt;T&gt; : IRepositoryCommand&lt;T&gt; 
{
    public void Execute(T entity)
    {
        // Logic for saving goes here
    }
}

public BatchSaveCommand&lt;T&gt; : IRepositoryCommand&lt;T&gt;
{
    public void Execute(IEnumerable&lt;T&gt; entities)
    {
        // Logic for batch saves go here
    }
}


which would then be called like this:

_myRepository.Execute(new SaveCommand());


My reasoning is that placing logic for the common data access operations (e.g. saving, deleting) gets to be so repetitive that right now I'm relying on a T4 template to recreate those everytime I have a new entity enter the playing field. This way I just define the most commonly used Data Access operations and then have any of my callers execute whatever action they need to execute.

Can you critique my work? I do have the tendency to overthink and overengineer things.
Although the command pattern you brought in makes it easy to create a 'flexible' Execute method. I wonder if it is really transparant to the ones who read your code.

Perhaps you can combine your two ideas, by implementing a certain ReadOnlyRepository using the command objects. So that the user of your interace keeps using:

repository-&gt;Update(SomeEntity);


While the repository implementation does:

repository.Execute(new UpdateCommand());


Consider, if you had to make a change to your later interface. Where would you need to update that in your code? In my suggestion it simply requires you to change it at one place. (since all the other code still uses the 'old' interface).

I hope my post makes sense :)