Безпроблемный шаблон Repository

Эта небольшая заметка является ответом на публикацию «Проблемный шаблон Repository».

Все основные идеи для приведенного ниже примера слоя Persistance / Repository для взяты из этой статьи. Этот код лишь частичной подкорректирован под потребности используемой мною архитектуры. Предлагаемое решение настолько простое, логичное и универсальное, что не могу его не привести после чтения статьи Александра.

Аналогичный подход для java-приложений хорошо описан здесь.

1. Рассмотрим слой Persistance, который состоит из 2х подслоёв — фабрики баз данных и репозитория данных.
/// <summary> базовый интерфейс для подслоя фабрики баз данных </summary>
public interface IDatabaseFactory
{
    /// <summary>Контекст базы данных (технология linq2sql)</summary>
    DataContext Get();
}

/// <summary> интерфейс для работы с базой данных Dpd </summary>
public interface IDpdDatabaseFactory : IDatabaseFactory
{
}

/// <summary>
/// Класс который фактически является обёрткой над DataContext нужной нам базы данных
/// </summary>
public class DpdDatabaseFactory : IDpdDatabaseFactory, IDisposable
{
    /// <summary>Контекст конкретной базы данных (технология linq2sql)</summary>
    private DpdDataContext context;

    /// <summary>Получение контекста базы данных</summary>
    public DataContext Get()
    {
        if (context == null)
        {
            context = new DpdDataContext();
        }
        return context;
    }

    public void Dispose()
    {
        if (context != null)
        {
            context.Dispose();
        }
    }
}

/// <summary> базовый интерфейс для подслоя репозитория </summary>
public interface IRepository<T> where T : class
{
    void Add(T entity);
    void Delete(T entity);
    T Get(Expression<Func<T, Boolean>> where);
    IEnumerable<T> GetAll();
    IEnumerable<T> GetMany(Expression<Func<T, bool>> where);
}

/// <summary> базовый класс для подслоя репозитория </summary>
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    /// <summary>Контекст бд</summary>
    protected DataContext context;

    /// <summary>таблицы с сущностями бд</summary>
    protected Table<TEntity> table;

    public BaseRepository(IDatabaseFactory dbFactory)
    {
        context = dbFactory.Get();
        table = context.GetTable<TEntity>();
    }

    public virtual void Add(TEntity entity)
    {
        if (entity != null)
        {
            table.InsertOnSubmit(entity);
        }
    }

    public virtual void Delete(TEntity entity)
    {
        if (entity != null)
        {
            table.DeleteOnSubmit(entity);
        }
    }

    public virtual TEntity Get(Expression<Func<TEntity, bool>> where)
    {
        return table.Where(where).FirstOrDefault();
    }

    public virtual IEnumerable<TEntity> GetMany(Expression<Func<TEntity, bool>> where)
    {
        return table.Where(where);
    }

    public virtual IEnumerable<TEntity> GetAll()
    {
        return table;
    }

}

/// <summary> репозиторий объектов бд Dpd </summary>
public class DpdRepository<TEntity> : BaseRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// При помощи механизма фреймворка IoC получаем экземпляр этого класса 
    /// (а в него вложен экземпляр DataContext нужной нам бд) с необходимым временем жизни
    /// Например со временем жизна Http запроса
    /// </summary>
    public DpdRepository() : base(UnityInstance.Container.Resolve<IDpdDatabaseFactory>())
    {
    }

    public DpdDataContext Context
    {
        get
        {
            var rprContext = (DpdDataContext) context;
            return rprContext;
        }
    }
}

/// <summary>создаём репозиторий для конкретного типа сущности модели домена </summary>
public class ProjectRepository : DpdRepository<Project>
{
}

2. Пример вызова методов репозитория в слое бизнес-логики
var repository = new ProjectRepository();
var list = repository.GetMany(item => item.parent_project_id == ProjectId).ToList();

3. Также можно вообще кардинально упростить код напрямую используя класс DpdRepository<...>
var list = (new DpdRepository<Project>()).GetMany(item => item.parent_project_id == ProjectId).ToList();
Метки:
ООП, .net, c#, java, Persistance, Repository