Entities Live in Repositories

by Damon Payne 6. March 2013 20:21

Related Articles:
A Different Kind of Entity Framework
Entities Live in Repositories (this article)


Regardless of where your data comes from, or winds up, it's good to have an abstraction around that storage mechanism. While it's unlikely your business is going to throw away it's investment in <<Big Enterprise DB>> any time soon, it's certainly a boon to testability. Much the of the modern development community has decided that the appropriate abstraction is the Repository.
An Entity that can be saved & retrieved by itself (without being part of some bigger object graph) should be fetched & stored using a repository.


For learned DDD people, we will revisit the concept of Aggregate Root another time.


I've seen a lot of simple repository definitions over time, and mine is particularly .NET and LINQ friendly. The only thing you may question is the separation of the Read and Write methods into different interfaces.  While I'm not necessarily dreaming of CQRS, it's wise to separate the read and write channels to avoid Liskov Substitution errors: many entities may not support write operations because they are read-only in your application. You could make the same arguments for Create and Delete, but I find read vs. write is a good place to start.

The Repository:

    /// <summary>
    /// A read-only store for retrieving IEntities
    /// </summary>
    public interface IRepository
    {
        /// <summary>
        /// Current work context
        /// </summary>
        IUnitOfWork UnitOfWork { get; set; }
    }

Repository of T

    /// <summary>
    /// Typed read-only operations for retrieving IEntities with a known Id type
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TId"></typeparam>
    public interface IRepository<TEntity, TId> : IRepository where TEntity : IEntity<TId>
    {
        /// <summary>
        /// Load & return all
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> Get();

        /// <summary>
        /// Load 1 by Id, or default(TEntity) if none found
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity Get(TId id);

        /// <summary>
        /// Return all TEntity matching the predicate May require an aggressive load.
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        IEnumerable<TEntity> Get(Func<TEntity, bool> predicate);
    }

Write repository of T

    /// <summary>
    /// Mutate operations for IEntity&lt;TId&gt;
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TId"></typeparam>
    public interface IWriteRepository<TEntity, TId> : IRepository where TEntity : IEntity<TId>
    {
        /// <summary>
        /// Create a new TEntity with an auto assigned id, or default(TId)
        /// </summary>
        /// <returns></returns>
        TEntity Create();

        /// <summary>
        /// Create a new TEntity with a given Id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        TEntity Create(TId id);

        /// <summary>
        /// Persist these targets
        /// </summary>
        /// <param name="targets"></param>
        void Save(IEnumerable<TEntity> targets);

        /// <summary>
        /// Persist this target
        /// </summary>
        /// <param name="target"></param>
        void Save(TEntity target);

        /// <summary>
        /// Remove these targets from persisted store
        /// </summary>
        /// <param name="targets"></param>
        void Delete(IEnumerable<TEntity> targets);

        /// <summary>
        /// Remove a single target from persisted store
        /// </summary>
        /// <param name="targets"></param>
        void Delete(TEntity targets);
    }

Wait, what's that IUnitOfWork in there? We'll have to save that for another day. This article, like the Entities article, was fairly short and
just establishes a simple baseline. In the next article we'll start to tackle the real substance of what this Shinto stuff is about. You can review these interfaces at https://github.com/damonrpayne/Shinto/tree/master/HandWaver.Shinto/Shinto.RepositoryModel

Tags:

Pingbacks and trackbacks (1)+

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


About the author

Damon Payne is a Microsoft MVP specializing in Smart Client solution architecture. 

INETA Community Speakers Program

Month List

Page List

flickr photostream