Entity Framework и репозиторий, безопасно ли передавать открытый контекст контроллерам?

#entity-framework #repository #objectcontext

#entity-framework #репозиторий #objectcontext

Вопрос:

В принципе, у меня есть репозиторий, который контролирует доступ к моей модели EF. Он создает ссылку, а затем, в зависимости от того, к какому репозиторию осуществляется доступ, возвращает запрошенный объект. Прямо сейчас я предоставляю метод IQueryable Get, который вернет объект непосредственно из текущего ObjectContext. Хорошая практика подсказывает мне, что я должен обернуть любое использование ObjectContext внутри инструкции using, чтобы убедиться, что оно правильно удалено, но когда я делаю это из репозитория, я получаю сообщение об ошибке, что ObjectContext уже удален к моменту его загрузки контроллером. Я удалил using, и затем он работает просто отлично, но я хотел бы знать, как обычно следует подходить к этому. Я хотел бы сохранить IQueryable return, поскольку мне может потребоваться выполнить различные команды над ним. Есть предложения? Помогает ли EF защитить меня от попадания в открытые соединения, если начнут поступать множественные HTTP-запросы?

Вывод ошибок:

 public IQueryable<IUser> Get
    {
        get
        {
            using (var context = new DrinkersPassportEntities(_connString))
            {
                return context.Users.AsQueryable();
            }
        }
    }
  

Работает, но не помогает мне спать по ночам:

 public IQueryable<IUser> Get
    {
        get
        {
            var context = new DrinkersPassportEntities(_connString);
            return context.Users.AsQueryable();
        }
    }
  

Все, что мой контроллер делает на данный момент, это:

     public ViewResult Index( )
    {

        return View(userRepo.Get);
    }
  

Ответ №1:

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

Вы действительно хотите убедиться, что вы избавляетесь от ObjectContext, иначе вы можете столкнуться с утечкой памяти (тем более, что она сохраняется для всех материализованных объектов).

Распространенным решением является использование времени жизни ObjectContext для каждого запроса. То есть сохраните ObjectContext в объекте запроса ASP .NET и обработайте HttpApplication.Событие EndRequest, при котором вы удаляете ObjectContext.

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

1. Я рассмотрю первую строку о том, что IQueryable возвращается из репозитория, поскольку я этого не знал. (это мой первый обзор всех реализуемых функций, т. Е.. mvc, ef 4, шаблон репозитория и внедрение зависимостей) Что касается ObjectContext для каждого запроса, не нарушит ли это часть моего разделения, если контекст либо завершается и / или генерируется в веб-приложении, а не в моем репозитории?

2. После гораздо большего чтения, основанного на вашем предложении относительно ObjectContext для каждого запроса, я нашел подходящий путь. Хотя комментарий Чада также технически корректен, в Интернете полно причин избегать IQueryable. В онлайн-предложениях говорится, что я должен абстрагировать HttpContext, чтобы создать CurrentContext с отложенной загрузкой, а затем внедрить его. Похоже, именно на это я потрачу завтрашний день. Еще не совсем понял, куда поместить мой ObjectContext, но, по крайней мере, он будет доступен из HttpContext. Я предполагаю, что я могу где-нибудь реализовать IDisposable. Спасибо!

3. Есть множество причин избегать IQueryables, и я уважаю некоторые из них, но, по моему мнению, невозможно поддерживать написание 500 методов репозитория, таких как GetCustomerById, GetCustomerByFirstName, GetCustomerByFirstNameAndLastName, GetCustomerByFirstNameLastNameAndMiddleName. В итоге вы получаете репозиторий, переполненный дублирующимися и неправильно используемыми функциями. Я бы предпочел предоставить IQueryable.

Ответ №2:

Уверен, что это безопасно. Многие люди отключаются и имеют 2-3 уровня для доступа к данным, в конце концов, просто убедитесь, что ваш код чистый. Как вы получаете свои объекты, зависит от вас, и я думаю, что прагматичный подход — лучший способ добиться этого. Я думаю, что наличие единого репозитория / класса обслуживания для данного типа, помогающего абстрагироваться от конкретных запросов, которые используются повторно, — это здорово, но нет ничего сложного в том, чтобы предоставлять контекст непосредственно в контроллере.