Я не согласен со всеми четырьмя пунктами:
Предотвращение автоматического закрытия/удаления соединений (будет закрыто в конце блока использования).
На мой взгляд, не имеет значения, размещаете ли вы контекст на уровне метода, уровне экземпляра репозитория или уровне запроса. (Конечно, вы должны размещать контекст в конце одного запроса — либо обернув метод репозитория в оператор using
, либо реализовав IDisposable
в классе репозитория (как вы предложили) и обернув экземпляр репозитория в операторе using
в действии контроллера, или путем создания экземпляра репозитория в конструкторе контроллера и удаления его в переопределении Dispose
класса контроллера, или путем создания экземпляра контекста, когда начинается запрос, и удаления его, когда запрос заканчивается (некоторые зависимости Контейнеры для инъекций помогут сделать эту работу.) Почему контекст должен "автоудаляться"? В настольном приложении возможно и распространено иметь контекст для каждого окна/представления, который может быть открыт часами.
Помогает заставить вас извлекать в память только то, что вам нужно для конкретного представления/модели представления, и с меньшим количеством циклов (вы получите ошибку соединения для всего, что вы пытаетесь отложить).
Честно говоря, я бы применил это, полностью отключив ленивую загрузку. Я не вижу никакой пользы от ленивой загрузки в веб-приложении, где клиент все равно отключен от сервера. В действиях вашего контроллера вы всегда знаете, что вам нужно загрузить, и можете использовать активную или явную загрузку. Чтобы избежать накладных расходов на память и повысить производительность, вы всегда можете отключить отслеживание изменений для запросов GET, поскольку EF все равно не может отслеживать изменения на веб-странице клиента.
Доступ к дочерним объектам в контроллере/представлении ограничен тем, что вы вызвали с помощью Include()
Что является скорее преимуществом, чем недостатком, потому что у вас нет нежелательных сюрпризов ленивой загрузки. Если вам нужно позже заполнить дочерние сущности в действиях контроллера, в зависимости от какого-то условия, вы можете загрузить их через дополнительные методы репозитория (LoadNavigationProperty
или что-то подобное) с тем же или даже новым контекстом.
Для таких страниц, как индекс приборной панели, который показывает информацию, собранную из многих таблиц (множество различных вызовов методов репозитория), мы добавим накладные расходы на создание и удаление множества контейнеров сущностей.
Создание контекстов — и я не думаю, что речь идет о сотнях или тысячах экземпляров — дешевая операция. Я бы назвал это очень теоретическими накладными расходами, которые на практике не играют никакой роли.
Я использовал оба упомянутых вами подхода в веб-приложениях, а также третий вариант, а именно создание единого контекста для каждого запроса и внедрение этого же контекста в каждый репозиторий/сервис, который мне нужен в действии контроллера. Все трое работали на меня.
Конечно, если вы используете несколько контекстов, вы должны быть осторожны, выполняя всю работу в одной и той же единице работы, чтобы избежать присоединения сущностей к нескольким контекстам, что приведет к хорошо известным исключениям. Обычно избежать таких ситуаций не составляет труда, но требует немного больше внимания, особенно при обработке POST-запросов.
В последнее время я использую контексты для каждого запроса, потому что это проще, и я просто не вижу пользы от очень узких контекстов, и я не вижу причин использовать более одной единицы работы для всей обработки запроса. Если бы мне по какой-то причине понадобилось несколько контекстов, я всегда мог бы создать специализированные методы, которые действуют со своим собственным контекстом вместо «контекста по умолчанию» запроса.
person
Slauma
schedule
18.04.2012