2

У меня есть визуальное студийное решение с использованием сплошного шаблона. У меня есть IRepository (реализация Crud), IDbFactory (используется репозиторием), IUnitOfWork. У меня также есть службы, которые используют репозитории для создания пользовательских запросов и сложной работы базы данных. Я использую также шаблон IoC с Ninject. В веб-контроллере mvc я использую только службы для доступа к базе данных. Репозиторий получает IDbFactory, который создает контекст EntityFramework. У меня есть некоторые проблемы:Принципы SOLID, шаблон хранилища и кеш EntityFramework в Asp Net Mvc

  • в службе, когда я должен получить доступ к двум таблицам для присоединиться к ним я должен использовать два хранилища, вызывая метод GETALL() обоих из них. В этом случае оба репозитория должны иметь один и тот же контекст EntityFramework.
  • Предыдущий случай указывает мне, что DbContext должен использоваться всеми репозиториями, поэтому я могу присоединиться к IQueryables в службе из разных репозиториев.
  • Для достижения этой цели я сконфигурирован в контейнере IoC, DbContext в однопользовательском режиме. Таким образом, каждый репозиторий имеет один и тот же DbContext.
  • Проблема с этим решением заключается в том, что у DbContext есть кеш. Таким образом, когда внешний процесс (отличный от веб-проекта) меняет мои данные, DbContext этого не понимает, и веб-проект иногда не показывает реальных данных.
  • Я прочитал о уничтожить DbContext в каждом вызове хранилища, но я не могу это сделать, потому что каждый репозиторий должен использовать тот же DbContext

я там что-то не так с моей структурой проекта? Это то, что я должен исправить в слое репозитория? Что я делаю? Проект находится в стадии разработки, поэтому я могу изменить архитектуру доступа к данным. Мне нравится использовать IQueryables в контроллере, так что пользователи фильтруют в сетках данных производят sql-запросы.

+1

CodeReview предлагает лучший форум для этих типов вопросов. Например: http://codereview.stackexchange.com/questions/11785/ef-code-first-with-repository-unitofwork-and-dbcontextfactory –

+1

Это классический пример того, почему создание IRepository обычно является пустой тратой времени. EF уже реализует репозиторий и единицу работы и абстрагирует db, так что теперь вы сбросили еще один слой абстракции сверху, чтобы достичь чего? Подождите, пока вы не начнете сохранять вещи в одном репозитории, и это сохраняет изменения в другом, потому что объекты привязаны к одному и тому же контексту. Если вы используете что-то вроде веб-сайта или службы, вы можете продлить срок службы DbContext на каждый запрос, но IRepository, как правило, больше проблем, чем его ценность, – Mant101

+0

еще одна проблема заключается в том, что ваш DbContext является синглом. Это означает, что каждый пользователь запускает тот же DbContext. ломает неотъемлемую часть работы в DBC-тексте. вы хотите создать dbcontext для каждой единицы работы. – Fran

ответ

4

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

Таким образом, ваша проектная структура является чрезмерной. Репозиторий/блок рабочих шаблонов предназначены для доступа к данным низкого уровня. ORM, как и Entity Framework, обрабатывает все это, и на самом деле Entity Framework уже реализует эти шаблоны. DbContext является единицей работы, и каждый DbSet является хранилищем. Добавление вашего собственного репозитория/единицы рабочего слоя поверх этого является излишним и ненужным. В ваших службах должен использоваться контекст Entity Framework напрямую. Даже тогда, имея множество услуг, вероятно, тоже не нужно, в зависимости от того, что они делают. Если все они работают с одним и тем же источником данных (т. Е. Контекстом платформы Entity Framework), и особенно если все они работают с одним и тем же контекстом Entity Framework, то все они должны быть полностью свернуты в один.

В моих личных проектах я использую один класс «службы» с универсальными методами для каждого уникального экземпляра контекста. Общие методы позволяют мне работать с любым объектом, принадлежащим к этому контексту, без необходимости добавления дополнительных экземпляров класса «service». Обеспечивая, что все реализует один или несколько интерфейсов и использует инъекцию зависимостей для удовлетворения ограничений интерфейса, базовый уровень данных полностью учитывается. У меня есть series of posts, который более подробно рассматривается, если вам интересно.

Я говорю все это, потому что кажется, что вы слишком сосредоточены на узорах и «лучших практиках».Это всего лишь руководства. Они похожи на тренировочные колеса на велосипеде. Все они основаны на различных принципах хорошего дизайна кода. Изучите и примените принципы и не беспокойтесь о проверке всех ящиков на каком-то списке шаблонов дизайна.

В качестве интересного в стороне, базовая кодовая база Stack Overflow фактически избегает ряда шаблонов (даже инъекции зависимостей), поскольку они ориентированы на лазерную фокусировку на сырую производительность, а некоторые шаблоны проектирования, когда они применяются, фактически препятствуют производительности. Дело в том, что разработка приложения должна основываться на потребностях конкретного приложения. Шаблоны проектирования должны применяться только в той мере, в какой они соответствуют потребностям вашего приложения, а не только потому, что вы думаете, что должны.

+0

Одна из причин, чтобы сложить шаблон UnitOfWork/Repository поверх структуры Entity Framework заключается в абстрагировании структуры сущности от другого кода. Это помогло мне в нескольких случаях. Как и когда я хотел обновить инфраструктуру сущности и произошли некоторые изменения, нарушившие единицу работы репозитория, я смог внести изменения один раз и не иметь проблем с остальной частью кода. Я также добавил некоторые объекты в DocumentDb и смог сделать репозиторий похожим на то, что делали существующие репозитории, а остальная часть кода выглядит в основном одинаковой при повторной передаче этих элементов. – MikeS

+0

Nope. Существуют и другие способы достижения одного и того же результата, а репозиторий/единица работы - наихудший путь. Как я описал в своем ответе, у меня есть один класс многократного использования, который может работать с * anything *, а Entity Framework полностью невидим. –

+1

Пожалуйста, объясните, как это «худший путь»? Он успешно работал для меня в течение нескольких лет без каких-либо жалоб? Нет ли возможного способа, который хуже, чем использование единицы работы? Вы не можете мечтать о том, что было бы хуже? – MikeS

0

Прежде всего, жизненный цикл DbContext должен продолжаться для всего бизнес-единицы, в приложениях MVC это для HttpRequest. Он предоставляет транзакцию с самого начала отправки запроса для получения ответа от пользователя.

Во-вторых, вы не должны иметь функцию GetAll() в базовом репозитории. Это очень неправильное решение, которое может повлиять на производительность вашего приложения. Вы должны создать такую ​​функцию, как: GetByQuery(Func<T, bool> whereQuery, int skip, int take), где T - общий тип вашего класса сущности. Кроме того, вы можете добавить параметр для сортировки.

Возможно, вам стоит подумать об отставке шаблона хранилища? Насколько велик ваш проект? Возможно ли изменить хранилище данных в будущем? Если нет, вы можете напрямую работать с DbContext в своих службах. Entity Framework - это своего рода реализация шаблона репозитория и UnitOfWork.

+0

, если его GetAll() возвращает IQueryable, то он может добавлять предикаты, пропускать, сортировать без штрафа за производительность, потому что EF использует отложенное выполнение. – Fran

+0

. Думаю, что штраф за производительность, о котором он говорит, загружает все записи таблицы. Если есть миллионы записей, это может быть очень дорогостоящим. Тем не менее, это все в том, как он используется. Даже если разрешить публичный доступ к чему-то вроде «GetByQuery», все равно можно использовать для получения * всех * записей, если вы просто не применяете никаких ограничений. Наличие метода «GetAll» само по себе не является проблемой; это просто должно быть ответственно. –

+0

правый. поэтому я упомянул IQueryable. Он не упоминает возвращаемый тип GetByQuery, который может быть IQueryable, а не списком . – Fran