Безпроблемный шаблон 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();
Tags:
ООП, .net, c#, java, Persistance, Repository

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.