Страницы

Поиск по вопросам

вторник, 26 ноября 2019 г.

Enitity Framework и Using


Подскажите, а является ли нормальной практикой плодить контексты using при работ
с Enitity Framework или правильнее передавать объекты сущностей в методы в качестве аргументов?

Вот это я подразумеваю под "Плодить контексты": 

DoWork()
{
    using (var db = new Entity())
    {
        // какая-то работа с сущностью
        ...
        DoWork2();
        ...
        // какая-то работа с сущностью
    }
}

DoWork2()
{
    using (var db = new Entity())
    {
        // какая-то работа с сущностью
        ...
    }
}

    


Ответы

Ответ 1



У многих, кто использует EF, возникает вопрос, как часто мы должны создавать DbContext, как определить оптимальное время жизни контекста. Возможные варианты времени жизни контекста: Функция Форма Поток Приложение Чтобы сделать правильный выбор, предлагаю рассмотреть несколько аспектов: Правильное разрушение контекста (вызов метода Dispose() контекста) Вызов метода Dispose является важным шагом при работе с классом DbContext. Используя конструкцию using, гарантируетcя своевременный вызов метода Dispose и тем самым освобождение неуправляемых ресурсов. using (MyContext ctx = new MyContext()) { … } Если забыть вызвать Dispose, то это может привести к утечке открытых соединений к БД и к неосвобождению неуправляемых ресурсов. do-i-have-to-call-dispose-on-dbcontext Стоимость операции создания нового класса контекста Операция создания нового контекста недорогая, потому что это, в основном, копировани ссылок метаданных из глобального кеша. Поэтому за стоимость этой операции не стоит беспокоиться. Использование памяти Чем дольше вы используете объект DbContext, тем больше памяти он занимает. Потом что он будет содержать все сущности (entity), о которых он знает, которые были запрошены через запросы, были добавлены либо присоединены. Поэтому держать долго контекст не рекомендуется. Потокобезопасность Класс DbContext не является потокобезопасным. Если мы используем контекст из нескольких потоков, то мы сами должны обеспечить сихронизацию доступа к контексту. Синхронизация данных с базой данных После создания контекста, если не предпринимать дополнительные меры, контекст н видит изменённые данные в БД, которые были сделаны извне. Создавая новый контекст, меры по синхронизации данных с БД предпринимать не нужно. Вот основные аспекты, которые пришли в голову. Поэтому контексты с коротким времене жизни при работе с EF являются нормальной практикой и часто используются при работе с EF.

Ответ 2



Context в EF, это, по сути, готовая реализация сразу нескольких паттернов: Repository Data Mapper Lazy Load ... Identity Map Unit of Work Последние два существенно ограничивают возможные варианты времени жизни контекста: Unit of Work Maintains a list of objects affected by a business transaction and coordinate the writing out of changes and the resolution of concurrency problems. Identity Map An Identity Map keeps a record of all objects that have been read from the databas in a single business transaction. Whenever you want an object, you check the Identity Map first to see if you already have it. Из двух цитат выше напрямую следует что контект должен жить ровно одну бизнес-операцию: Если он будет жить меньше ("плодить контексты" в вопросе) - то часть кода операции не увидит измененения, внесенные до нее. Если он будет жить дольше, на протяжении нескольких операций - то другие операци будут видеть неактуальные данные (из-за Identity Map) или наоборот, будт видеть изменения, которые еще не были сохранены. Что такое бизнес-операция (бизнес-транзакция) - зависит от конкретной предметно области. Это не транзакция в терминах баз данных, а более широкое понятие - некое целостное действие в терминах предметной области. Обычно это вызов кода сервиса / фасада в BL - DoWork, где Work - это какая-то цельная операция, действие. Т.е. обычно это вызов функции верхнего уровня в вашем приложении. Соображения использования памяти, потокобезопасности, стоимости создания, синхронизаци с базой данных - полностью вторичны, и не должны служить основанием для выбора времени жизни контекста. Контекст - это попытка отразить в коде цельную операцию из предметной области. Предметно области все равно, сделаете вы это в одном потоке или в разных, потратите при этом мног памяти или мало, придется ли вам при этом писать огромные методы, или обойдеться парой строк - это никак не влияет на целостность операции. Соответственно, и на выбор времени жизни контекста влиять не должно. Выбор контейнера в коде, в рамках которого живет контектст - функция, форма, поток запрос, приложение - тоже вторичен. Он должне быть следствием, а не причиной времени жизни контекста. Если конкретная функция (DoWork) соответствует бизнес-операции - она должна контролировать время жизни контекста. Если нет (DoWork2) - то нет. Если бизнес-операция растягивается на время отображения формы - то время жизни контекста должно совпадать с формой, и контекст вполне может быть полем формы. Если нет - то нет. Если вы запускаете фоновые операция в отдельном потоке - то время жизни скорее всег совпадет с временем жизни потока. Но не потому, что это фоновая операция, а потому что это фоновая операция. Если у вас консольное приложение, которое выполняет ровно одну бизнес-операцию то вполне разумно использовать один контекст на приложение.

Ответ 3



Ну а с другой стороны: Если загрузка каких-то объектов из базы и их изменение с сохранением происходит разных местах приложения и еще и по инициативе пользователя, т.е. может быть значительн разнесено по времени - то придётся каждый раз при создании контекста снова загружат нужные объекты, например используя метод Find с сохраненным ранее ключом и работат уже с обновленными объектами. Если же контекст держать открытым, то этого не потребуется. Только нужно будет поработать над гарантированным закрытием этого долгоживущего контекста как только он перестанет быть нужным. Наверно тут нужен компромис - может быть кэш с выгрузкой контекста (контекстов) по времени, хотя это не проще, чем многократная загрузка объектов, но производительнее.

Комментариев нет:

Отправить комментарий