I've been using this variation of the Repository pattern for over a year now:
public interface IReadOnlyRepository<T, in TId>
where T : AbstractEntity<TId>
{
T Get( TId id );
IEnumerable<T> GetAll();
}
/// <summary>
/// Defines a generic repository interface for
/// classes solely in charge of getting and processing data from a data source
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TId">The type of the id.</typeparam>
public interface IRepository<T, in TId> : IReadOnlyRepository<T, TId> where T : AbstractEntity<TId>
{
/// <summary>
/// Determines whether the specified entity has duplicates.
/// </summary>
/// <param name="entity">The entity.</param>
/// <returns>
/// <c>true</c> if the specified entity has duplicates; otherwise, <c>false</c>.
/// </returns>
bool HasDuplicates(T entity);
/// <summary>
/// Inserts the specified entity.
/// </summary>
/// <param name="entity">The entity.</param>
void Save( T entity );
/// <summary>
/// Inserts the entity or updates it if it already exists.
/// </summary>
/// <param name="entity">The entity.</param>
T SaveOrUpdate( T entity );
/// <summary>
/// Updates the specified entity.
/// </summary>
/// <param name="entity">The entity.</param>
/// <returns></returns>
T Update(T entity);
/// <summary>
/// Deletes the specified entity from the data source.
/// </summary>
/// <param name="entity">The entity.</param>
void Delete(T entity);
/// <summary>
/// Deletes the entity with the specified id.
/// </summary>
/// <param name="id">The id.</param>
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<T, in TId> : IReadOnlyRepository<T, TId> where T : AbstractEntity<TId>
{
void Execute(IRepositoryCommand command);
void Execute(IBatchRepositoryCommand command);
}
public interface IRepositoryCommand<T>
{
void Execute(T entity);
}
public interface IBatchRepositoryCommand<T>
{
void Execute(IEnumerable<T> entities);
}
public SaveCommand<T> : IRepositoryCommand<T>
{
public void Execute(T entity)
{
// Logic for saving goes here
}
}
public BatchSaveCommand<T> : IRepositoryCommand<T>
{
public void Execute(IEnumerable<T> 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.