Как создать статический UnitOfWork для Entity Framework 4?
Учитывая этот класс
public class XQueries
{
public IQueryable Query1()
{
using (XEntities context = new XEntities())
{
return something;
}
}
public IQueryable Query2()
{
using (XEntities context = new XEntities())
{
return somethingElse;
}
}
}
Соединение с базой данных создано для каждого (XEntities context = new XEntities()) {...}? Если да, то как правильно создать статический класс UnitOfWork, чтобы существовало только 1 соединение?
2 ответа
Вы не можете создать статическую единицу работы, потому что по определению единица работы - это недолговечный объект. Потому что EF ObjectContext
разработан вокруг единицы работы шаблона, это плохая идея иметь один ObjectContext
экземпляр в течение срока действия приложения. На это есть несколько причин.
Прежде всего, ObjectContext
класс не является потокобезопасным. Это означает, что во время единицы работы одного пользователя (например, в веб-приложении) другой пользователь может зафиксировать свою единицу работы. Когда они разделяют одно и то же ObjectContext
, это означает, что в этой ситуации сохраняется только половина изменений, и изменения не являются транзакционными. Когда вам повезет, ObjectContext
не удается и выдает исключение. Когда вам не везет, вы портите ObjectContext
и сохраните и загрузите дерьмо из вашей базы данных и в нее, и узнайте, когда ваше приложение работает в рабочей среде (конечно, во время тестирования и постановки все всегда работает).
Во-вторых, ObjectContext
имеет механизм кэширования, предназначенный для того, чтобы он был недолгим Когда объект извлекается из базы данных, он остается в ObjectContext
кеш, пока этот экземпляр не будет собран. Когда вы сохраняете этот экземпляр в течение длительного периода времени, сущности устаревают. Особенно если этот конкретный ObjectContext
экземпляр не единственный, пишущий в эту базу данных.
Entity Framework открывает соединения только при необходимости, например, для выполнения запроса или для вызова SaveChanges, а затем закрывает соединение, когда операция завершена.
Из книги Мартина Фаулера "Образцы архитектуры корпоративных приложений в отношении единицы работы".
Когда вы извлекаете данные из базы данных и из нее, важно следить за тем, что вы изменили; в противном случае эти данные не будут записаны обратно в базу данных. Точно так же вы должны вставить новые объекты, которые вы создаете, и удалить любые объекты, которые вы удаляете.
Вы можете изменять базу данных при каждом изменении вашей объектной модели, но это может привести к множеству очень маленьких обращений к базе данных, которые в итоге оказываются очень медленными. Кроме того, требуется, чтобы у вас была открытая транзакция для всего взаимодействия, что нецелесообразно, если у вас есть бизнес-транзакция, охватывающая несколько запросов. Ситуация еще хуже, если вам нужно отслеживать объекты, которые вы прочитали, чтобы избежать непоследовательного чтения.
Единица работы отслеживает все, что вы делаете во время бизнес-транзакции, которая может повлиять на базу данных. Когда вы закончите, он выяснит все, что нужно сделать, чтобы изменить базу данных в результате вашей работы.
Всякий раз, когда я использую Entity Framework для клиентов (что я признаю редко), объект ObjectContext является реализацией единицы работы для системы. То есть ObjectContext будет в некоторой степени соответствовать трем утверждениям выше. Вместо того, чтобы слишком концентрироваться на абсолютно правильном определении, использование ObjectContext немного облегчает вам задачу.
Проведите некоторое исследование шаблонов DI/IoC и Repository, это даст вам больше гибкости в решении вашей проблемы.