Управление Entity Framework ObjectContext в ASP.NET - PullRequest
4 голосов
/ 19 января 2012

Я использую Entity Framework для приложения веб-форм ASP.NET, и мне интересно, как мне поступить с ObjectContext и его временем жизни. Например, у меня есть класс InviteService, который управляет приглашениями, такими как создание и принятие приглашений. Сам класс находится в другом проекте / пространстве имен из веб-проекта. Метод InviteUsers() создает Invite сущности для списка пользователей, вызывает хранилище для сохранения их в базе данных и отправляет каждому пользователю ссылку для приглашения.

Метод вызывается из Page, когда пользователь нажимает кнопку приглашения.

Я хотел бы знать, как я должен использовать ObjectContext

  1. Создание нового ObjectContext на странице при каждом запросе, передача его в качестве параметра конструктору класса InviteService, а затем его удаление в методе Render.
  2. То же, что и выше, но вместо того, чтобы устанавливать его через конструктор, передавая его в качестве параметра каждому методу.
  3. Создайте отдельный Objectcontext в каждом методе с using блоком.

Первый вариант мне кажется наилучшим, исходя из ответа Ладислава здесь: Платформа сущностей и пул соединений Но вариант 3 также кажется действительным, поскольку, насколько мне известно, новые подключения к базе данных не создаются из-за пула подключений.

Ответы [ 2 ]

6 голосов
/ 19 января 2012

Нет ничего необычного в создании одного ObjectContext для каждого веб-запроса. Я делаю это в своих веб-приложениях. Тем не менее, ИМО, страница должна ничего не знать о ObjectContext.

Поскольку вы уже говорите о внедрении контекста в конструктор службы, взгляните на внедрение зависимостей (если вы его еще не используете). Когда вы используете контейнер внедрения зависимостей, вы можете позволить контейнеру создать этот сервис для вас и внедрить контекст объекта в этот контейнер. Единственное, что ваша страница должна сделать, это запросить этот сервис из контейнера (в идеале, вы бы даже позволили этому сервису внедриться в конструктор этой страницы, но это невозможно с веб-формами).

Ваша страница будет выглядеть так:

public class MyPage : Page
{
    private readonly IMyService service;

    public MyPage()
    {
        this.service = Global.GetInstance<IMyService>();
    }

    protected void Btn1_OnClick(object s, EventArgs e)
    {
        this.service.DoYourThing(this.TextBox1.Text);
    }
}

В пути запуска (Global.asax) вашего приложения вы можете настроить структуру внедрения зависимостей следующим образом:

private static Container Container;

public static T GetInstance<T>() where T : class
{
    return container.GetInstance<T>();
}

void Application_Start(object sender, EventArgs e) 
{
    var container = new Container();

    string connectionString = ConfigurationManager
        .ConnectionStrings["MyCon"].ConnectionString;

    // Allow the container to resolve your context and
    // tell it to create a single instance per request.
    container.RegisterPerWebRequest<MyContext>(() =>
        new MyContext(connectionString));

    // Tell the container to return a new instance of
    // MyRealService every time a IMyService is requested.
    // When MyContext is a constructor argument, it will
    // be injected into MyRealService.
    container.Register<IMyService, MyRealService>();

    Container = container;
}

В этих примерах я использовал контейнер внедрения зависимостей Simple Injector , хотя подойдет любой контейнер DI. RegisterPerWebRequest не является частью базовой библиотеки, но доступен в виде (NuGet) пакета расширения . Пакет гарантирует, что ваш ObjectContext будет удален после завершения веб-запроса.

Поначалу это может показаться сложным, но при этом веб-странице вообще не нужно беспокоиться о деталях создания и утилизации ObjectContext.

Далее, поместите логику, которая выполняет сценарий использования, в один класс: команду. Пусть команда (или система) обеспечивает атомарность этой операции. Не позволяйте странице отвечать за это и не фиксируйте в конце запроса, потому что в этот момент вы не будете знать, нормально ли будет вызывать commit. Нет, пусть команда справится с этим сама. Вот статья о написании бизнес-команд .

Этот совет относится и к ASP.NET MVC, хотя вы не должны вызывать Global.GetInstance<IMyService>() внутри конструктора контроллера, а просто использовать внедрение конструктора (поскольку MVC имеет большую поддержку для этого) и использовать пакет интеграции MVC3 .

Также взгляните на этот вопрос Stackoverflow , в котором говорится о выборе между IObjectContextFactory или ObjectContext на запрос.

2 голосов
/ 19 января 2012

1 - лучшее решение. В мире NHibernate называется session-per-request.

Вы можете создать экземпляр ObjectContext в BeginRequest и сбросить / зафиксировать его в EndRequest.

1 лучше, чем 3, потому что вы начинаете работать с ORM (Entity Framework в вашем случае), когда приходит запрос. Затем вы добавляете объект в дерево, изменяете класс, удаляете и т. Д. В течение жизненного цикла ВСЕЙ страницы.

Только во время EndRequest вы фиксируете ВСЕ свои изменения только в одном пакете.

РЕДАКТИРОВАТЬ: как говорит @Steven, не идеально подходит для обработки исключений во время фиксации.

Предположим, у вас есть веб-форма с кнопкой сохранения:

  • создать ObjectContext во время запроса BeginRequest
  • вызов коммита в обработчике команд сохранения
  • просто закройте / утилизируйте ObjectContext во время EndRequest
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...