Шаблон репозитория для приложения ASP MVC

Это больше касается дизайна.

Я создаю приложение, и я создал свою структуру шаблонов репозитория следующим образом:

Мое пространство имен Core - это сборка слоев DAL/Repository/BusinessLogic.

Кстати, я использую Dapper.NET micro ORM в качестве своего соединения для передачи данных, поэтому вы увидите расширение для моего объекта SqlConnection.

Для доступа к данным я создал базовый класс репозитория:

namespace Core
{
    public class BaseRepository<T>: IDisposable where T : BaseEntity 
    {
        protected SqlConnection conn = null;


        #region Constructors
        public BaseRepository() : this("LOCAL")
        {

        }

        public BaseRepository(string configurationKey = "LOCAL")
        {
            conn = new SqlConnection(ConfigurationManager.ConnectionStrings[configurationKey].ConnectionString);
        }
        #endregion

        #region IDisposable
        public void Dispose()
        {
            conn.Dispose();
        }
        #endregion


        /// <summary>
        /// returns a list of entities
        /// </summary>
        /// <typeparam name="T">BaseEntity type</typeparam>
        /// <param name="sproc">optional parameters, stored procedure name.</param>
        /// <returns>BaseEntity</returns>
        protected virtual IEnumerable<T> GetListEntity(string sproc = null)
        {
            string storedProcName = string.Empty;
            if (sproc == null)
            {
                storedProcName = "[dbo].sp_GetList_" + typeof(T).ToString().Replace("Core.",string.Empty);
            }
            else
            {
                storedProcName = sproc;
            }

            IEnumerable<T> items = new List<T>();
            try
            {
                conn.Open();
                items = conn.Query<T>(storedProcName,
                                                     commandType: CommandType.StoredProcedure);
                conn.Close();
            }
            finally
            {
                conn.Close();
            }


            return items;
        }


    }
}

И для каждого имеющегося у меня объекта, скажем ExtendedUser, Messages, я создаю его на паре Interface-Class следующим образом:

namespace Core
{
    public class ExtendedUserRepository : BaseRepository<UsersExtended>,IExtendedUserRepository
    {

        public ExtendedUserRepository() : this("PROD") 
        {
        }

        public ExtendedUserRepository(string configurationKey) : base(configurationKey)
        {
        }


        public UsersExtended GetExtendedUser(string username)
        {
            var list = GetListEntity().SingleOrDefault(u => u.Username == username);
            return list;
        }

        public UsersExtended GetExtendedUser(Guid userid)
        {
            throw new NotImplementedException();
        }


        public List<UsersExtended> GetListExtendedUser()
        {
            throw new NotImplementedException();
        }
    }
}

и т.п.

Приведенный выше код является лишь одним из объектов:ExtendedUser.

Вопрос заключается в следующем: я должен создать пару Interface-ClassThatImplemenetsInterface для каждой сущности, которая у меня есть? или у меня должен быть только один RepositoryClass и один интерфейс IRepository со всеми моими методами от всех моих сущностей?

2 ответа

Решение

Я не думаю, что вам нужно создавать интерфейс без причины. Я даже не понимаю, зачем вам нужен базовый класс репозитория здесь. Я даже думаю, что это не репозиторий, а DAL (Data Access Layer), но это определенное утверждение.

Я думаю, что хорошая реализация DAL должна отделить структуру базы данных от структуры бизнес-логики, но жесткое кодирование шаблона sp_GetList_XXXEntityNameXXX или передача имени хранимой процедуры за пределы DAL не разъединяет.

Вы очень оптимистичны или ваше приложение действительно простое, если вы думаете, что все списки сущностей получены одним способом, и вам всегда потребуется полный набор сущностей в бизнес-логике без каких-либо параметров.

Отделение интерфейса от реализации необходимо только в том случае, если вы планируете заменить / обернуть различные реализации или смешать несколько интерфейсов в одном классе. В противном случае это не требуется.

Не думайте с точки зрения сущностей при создании репозиториев. Репозиторий содержит бизнес-логику и должен быть построен на основе сценариев использования. Наличие таких классов, как у вас, больше относится к уровню доступа к данным, а DAL построен на запросах, которые вам понадобятся в бизнес-логике. Возможно, вам никогда не понадобится список ВСЕХ пользователей одновременно, но очень часто потребуется список активных пользователей, привилегированных пользователей и т. Д.

Действительно сложно предсказать, какие запросы вам понадобятся, поэтому я предпочитаю начинать разработку с бизнес-логики и, кстати, добавить методы DAL.

Система со сложной моделью домена часто получает пользу от уровня, такого как предоставляемый Data Mapper (165), который изолирует объекты домена от деталей кода доступа к базе данных. В таких системах может оказаться целесообразным создать еще один уровень абстракции над уровнем отображения, где сосредоточен код построения запроса.

http://martinfowler.com/eaaCatalog/repository.html

С общим репозиторием у вас могут быть общие методы, такие как findBy(array('id' => 1)), findOneBy(array('email' => 'john@bar.com')), findById(), findAll() и так далее. Действительно, у него будет один интерфейс.

Вам всегда нужно будет создать конкретную реализацию, которая будет указывать, какой объект домена будет управляться хранилищем, чтобы выполнить это. getUsersRepository().findAll()

Более того, если вам нужны более сложные запросы, вы можете создать новые методы для конкретной реализации, такие как findMostActiveUsers() а затем повторно использовать его в вашем приложении.

Теперь, отвечая на ваш вопрос:

Ваше приложение будет ожидать по крайней мере один интерфейс (тот общий, с общими методами). Но если вам удастся использовать определенные методы, например, тот, который я только что упомянул выше, вам лучше иметь другой интерфейс (например, RepositoryInterface и UsersRepositoryInteface).

Имея это в виду, вы будете зависеть только от интерфейса репозитория. Конструкция запроса будет инкапсулирована конкретной реализацией. Таким образом, вы сможете изменить свою реализацию репозитория (например, используя полноценный ORM), не затрагивая остальную часть вашего приложения.

Другие вопросы по тегам