Подтвердить что ты не робот

Когда я должен создать новый DbContext()

В настоящее время я использую DbContext, подобный этому:

namespace Models
{
    public class ContextDB: DbContext
    {

        public DbSet<User> Users { get; set; }
        public DbSet<UserRole> UserRoles { get; set; }

        public ContextDB()
        {

        }
    }
}

Затем я использую следующую строку в верхней части ВСЕ моих контроллеров, которым необходим доступ к базе данных. Я также использую его в своем классе UserRepository, который содержит все методы, относящиеся к пользователю (например, получение активного пользователя, проверка его ролей и т.д.):

ContextDB _db = new ContextDB();

Думая об этом.. происходят случаи, когда один посетитель может иметь несколько активных объектов DbContexts. если ГЭС посещает контроллер, который использует UserRepository.. это может быть не лучшее из идей, и у меня есть несколько вопросов об этом

  • Когда мне нужно создать новый DbContext/должен ли я иметь один глобальный контекст, который я просматриваю?
  • Могу ли я иметь один глобальный контекст, который я буду использовать во всех местах?
  • Это приводит к поражению производительности?
  • Как все это делают?
4b9b3361

Ответ 1

Я использую базовый контроллер, который предоставляет свойство DataBase, к которому могут обращаться производные контроллеры.

public abstract class BaseController : Controller
{
    public BaseController()
    {
        Database = new DatabaseContext();
    }

    protected DatabaseContext Database { get; set; }

    protected override void Dispose(bool disposing)
    {
        Database.Dispose();
        base.Dispose(disposing);
    }
}

Все контроллеры в моем приложении получают от BaseController и используются следующим образом:

public class UserController : BaseController
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(Database.Users.OrderBy(p => p.Name).ToList());
    }
}

Теперь, чтобы ответить на ваши вопросы:

Когда я должен создать новый DbContext/должен ли я иметь один глобальный контекст что я прохожу?

Контекст должен быть создан для каждого запроса. Создайте контекст, сделайте то, что вам нужно сделать, а затем избавьтесь от него. В решении базового класса я использую вас только для того, чтобы беспокоиться об использовании контекста.

Не пытайтесь использовать глобальный контекст (это не работает веб-приложения).

Можно ли использовать один глобальный контекст, который я использую во всех местах?

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

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

Лично я предпочитаю показывать DbContext напрямую, поскольку большинство примеров репозитория, которые я видел, просто заканчиваются как тонкие обертки вокруг DbContext в любом случае.

Из-за этого пострадает производительность?

В первый раз, когда создается DbContext, довольно дорого, но как только это было сделано, большая часть информации кэшируется, поэтому последующие экземпляры намного быстрее. вы, скорее всего, увидите проблемы с производительностью из-за сохранения контекста, чем от создания экземпляра каждый раз, когда вам нужен доступ к вашей базе данных.

Как все это делают?

Это зависит.

Некоторые люди предпочитают использовать инфраструктуру внедрения зависимостей, чтобы передать конкретный экземпляр своего контекста своему контроллеру при его создании. Оба варианта в порядке. Mine более подходит для приложений малого масштаба, где вы знаете, что используемая конкретная база данных не изменится.

некоторые могут утверждать, что вы не можете это знать, поэтому метод инъекции зависимостей лучше, так как он делает ваше приложение более устойчивым к изменению. Мое мнение по этому поводу заключается в том, что он, вероятно, не изменится (SQL Server и Entity Framework вряд ли неясны), и что мое время лучше всего использовать для написания кода, характерного для моего приложения.

Ответ 2

Сейчас я пытаюсь использовать этот подход, который позволяет избежать создания контекста при вызове действий, которые его не используют.

public abstract class BaseController : Controller
{
    public BaseController() { }

    private DatabaseContext _database;
    protected DatabaseContext Database
    {
        get
        {
            if (_database == null)
                _database = new DatabaseContext();
            return _database;
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (_database != null)
            _database.Dispose();
        base.Dispose(disposing);
    }
}

Ответ 3

Это, очевидно, более старый вопрос, но если вы используете DI, вы можете сделать что-то вроде этого и охватить все ваши объекты для срока службы запроса

 public class UnitOfWorkAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
            context.BeginTransaction();
        }

        public override void OnActionExecuted(HttpActionExecutedContext actionContext)
        {
            var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
            context.CloseTransaction(actionContext.Exception);
        }
    }

Ответ 4

Я пытаюсь ответить исходя из собственного опыта.

1. Когда я должен создать новый DbContext/у меня должен быть один глобальный контекст, который я передаю?

Контекст должен быть введен путем внедрения зависимостей и не должен создаваться вами самими. Лучшая практика заключается в том, чтобы он создавался как сервис с ограниченным доступом путем внедрения зависимости. (См. Мой ответ на вопрос 4)

Также рассмотрите возможность использования правильной многоуровневой структуры приложения, такой как Controller> BusinessLogic> Repository. В этом случае это будет не тот случай, когда ваш контроллер получает db-контекст, а вместо этого хранилище. Инъекция/создание db-контекста в контроллере говорит мне, что ваша прикладная архитектура сочетает в себе много обязанностей в одном месте, что - ни при каких обстоятельствах - я не могу рекомендовать.

2. Могу ли я иметь один глобальный контекст, который я могу использовать во всех местах?

Да, можно, но вопрос должен быть " Должен ли я..." → НЕТ. Контекст предназначен для использования в каждом запросе для изменения вашего хранилища, а затем его снова нет.

3. Влияет ли это на производительность?

Да, это так, потому что DBContext просто не создан для того, чтобы быть глобальным. Он хранит все данные, которые были введены или запрошены в нем, пока он не будет уничтожен. Это означает, что глобальный контекст будет становиться все больше и больше, операции с ним будут выполняться все медленнее и медленнее, пока вы не получите исключения из нехватки памяти или не умрете, потому что все замедлилось до ползания.

Вы также получите исключения и множество ошибок, когда несколько потоков обращаются к одному и тому же контексту одновременно.

4. Как все остальные делают это?

DBContext внедряется посредством внедрения зависимостей фабрикой; область видимости:

services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));

Я надеюсь, что мои ответы, где помочь.