ASP.NET MVC с использованием шаблона репозитория

В настоящее время я использую EF и использую его datacontext непосредственно во всех своих действиях, но так как я начал читать о свободной связи и тестируемости, я думаю, что это не лучший способ. Я пытаюсь понять все pro и con, прежде чем начать рефакторинг всего моего текущего кода.

Проблема 1: Принимая во внимание, что каждый объект нуждается в собственном репозитории и, следовательно, должен настроить собственное подключение к источнику данных (позволяет использовать базу данных с использованием EF), не даст ли много накладных расходов, если мне нужны данные из 5 разных объектов на одной странице?

Проблема 2: То, что я видел во всех примерах, которые я нашел в Интернете, заключается в том, что большинство людей (даже таких, как Шанселман) реализуют шаблон хранилища, используя классы сущностей, которые генерируются либо LINQ, либо EF, не лишает ли это цели шаблона репозитория с касается ослабления сцепления? С другой стороны, какова альтернатива, используя классы POCO в сочетании с, например, AutoMapper? (меня это немного пугает)

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

Ответ 2

ObjectContext использует пул соединений, поэтому он не будет таким неэффективным, как вы думаете. Кроме того, SQL-серверы (т.е. MSSQL) действительно оптимизированы для нескольких одновременных подключений.

Что касается того, как реализовать его, я бы пошел с некоторым интерфейсом IRepository. Затем вы можете создавать определенные интерфейсы, т.е. PostRepository > IRepository, и, наконец, реализовать это в конкретных классах (например, настоящий класс и поддельный в памяти для тестирования).

Ответ 3

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

Для реализации Scott H я предполагаю, что вы имеете в виду приложение Nerd Dinner, которое по его собственному признанию на самом деле не является шаблоном репозитория.

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

В пуристских терминах вы создадите POCOs, которые вы вернетесь из репозитория в ваш BL, используя интерфейс для определения контракта репозитория, который вы могли бы передать и использовать интерфейс, а не конкретную реализацию. Это позволит вам передать любой объект, который реализовал интерфейс репозитория, будь то ваш репозиторий или вымышленный репозиторий.

В реальности я использую репозиторий с MVC с Linq to SQL в качестве моего хранилища, который позволяет мне проявлять определенную гибкость над фактическим хранилищем, поэтому я использую объекты L2S, созданные вручную, в моем BL, у них есть дополнительные поля и функциональные возможности, которые не являются "Я остался в резервном магазине. Таким образом, я получаю отличную функциональность от аспектов L2S, отслеживания изменений, иерархии объектов и т.д., А также позволяю мне подменять издевательский репозиторий для TDD.

Ответ 4

Вы ударяете ноготь по голове, идентифицируя трудности с использованием Entities в качестве бизнес-объектов. После долгих проб и ошибок, здесь шаблон, который мы поселились, который работал очень хорошо для нас:

Наше приложение разделено на модули, и каждый модуль делится на три уровня: Web (front-end), Core (бизнес) и Data. В нашем случае каждому из этих уровней присваивается свой собственный проект, поэтому существует жесткое правоприменение, предотвращающее плотную связь наших зависимостей.

Уровень Core содержит классы утилиты, POCOs и интерфейсы репозитория.

Уровень Веб использует эти классы и интерфейсы для получения необходимой им информации. Например, контроллер MVC может использовать конкретный интерфейс репозитория в качестве аргумента конструктора, поэтому наша инфраструктура IoC внедряет правильную реализацию этого репозитория при создании контроллера. Интерфейс репозитория определяет методы выбора, которые возвращают наши объекты POCO (также определенные в базовом бизнес-уровне).

Уровень Данные отвечает за реализацию интерфейсов репозитория, определенных в уровне ядра. Он имеет контекст Entity Framework, который представляет наше хранилище данных, но вместо того, чтобы возвращать объекты (которые являются технически "объектами данных" ), он возвращает POCO, определенные в базовом слое (наши "бизнес-объекты" ).

Чтобы уменьшить повторение, мы имеем абстрактный, общий EntityMapper класс, который предоставляет базовую функциональность для отображения объектов в POCOs. Это делает большинство наших реализаций репозитория предельно простым. Например:

public class EditLayoutChannelEntMapper : EntityMapper<Entity.LayoutChannel, EditLayoutChannel>,
    IEditLayoutChannelRepository
{
    protected override System.Linq.Expressions.Expression<Func<Entity.LayoutChannel, EditLayoutChannel>> Selector
    {
        get
        {
            return lc => new EditLayoutChannel
                             {
                                 LayoutChannelId = lc.LayoutChannelId,
                                 LayoutDisplayColumnId = lc.LayoutDisplayColId,
                                 ChannelKey = lc.PortalChannelKey,
                                 SortOrder = lc.Priority
                             };
        }
    }
    public EditLayoutChannel GetById(int layoutChannelId)
    {
        return SelectSingle(c => c.LayoutChannelId == layoutChannelId);
    }
}

Благодаря методам, реализованным базовым классом EntityMapper, вышеупомянутый репозиторий реализует следующий интерфейс:

public interface IEditLayoutChannelRepository
{
    EditLayoutChannel GetById(int layoutChannelId);
    void Update(EditLayoutChannel editLayoutChannel);
    int Insert(EditLayoutChannel editLayoutChannel);
    void Delete(EditLayoutChannel layoutChannel);
}

EntityMappers делают очень мало в своих конструкторах, поэтому хорошо, если контроллер имеет несколько зависимостей репозитория. Мало того, что Entity Framework повторно использует соединения, но сами Контексты Entity создаются только при вызове одного из методов репозитория.

Каждый модуль также имеет специальный проект Test, который содержит модульные тесты для классов в этих трех уровнях. Мы даже придумали способ сделать наши репозитории и другие классы доступа к данным несколько проверенными на единицу. Теперь, когда у нас установлена ​​эта базовая инфраструктура, добавление функциональности в наше веб-приложение, как правило, довольно плавное и не слишком подверженное ошибкам.

Ответ 5

Проблема 2: способ избежать этого будет использовать что-то вроде ADO.NET С# POCO Entity Generator".

Ответ 6

Пул соединений ADO.NET будет управлять соединениями за кадром. В принципе, не имеет значения, сколько разных объектов (и, следовательно, репозиториев с их собственным контекстом) вы используете; каждая операция DB будет принимать соединения из одного пула.

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