В настоящее время я использую 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 / должен ли я иметь один глобальный контекст, который я передаю?
- Могу ли я иметь один глобальный контекст, который можно использовать повсюду?
- Это вызывает снижение производительности?
- Как все остальные это делают?
DbContext
каждого запроса. Я бы также создал сервисный слой. Отметьте этот ТАК вопрос и ответОтветы:
Я использую базовый контроллер, который предоставляет
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
любом случае просто превращаются в тонкие оболочки .Первое создание a
DbContext
довольно дорого, но как только это было сделано, большая часть информации кэшируется, так что последующие экземпляры выполняются намного быстрее. у вас больше шансов увидеть проблемы с производительностью из-за сохранения контекста, чем из-за его экземпляра каждый раз, когда вам нужен доступ к своей базе данных.Это зависит.
Некоторые люди предпочитают использовать структуру внедрения зависимостей для передачи конкретного экземпляра своего контекста своему контроллеру при его создании. Оба варианта подходят. Мой больше подходит для небольшого приложения, когда вы знаете, что конкретная используемая база данных не изменится.
некоторые могут возразить, что вы не можете этого знать, и именно поэтому метод внедрения зависимостей лучше, поскольку он делает ваше приложение более устойчивым к изменениям. Мое мнение по этому поводу состоит в том, что это, вероятно, не изменится (SQL-сервер и Entity Framework вряд ли являются непонятными) и что мое время лучше всего потратить на написание кода, специфичного для моего приложения.
источник
Я пытаюсь ответить, исходя из собственного опыта.
1. Когда мне следует создать новый DbContext / должен ли я иметь один глобальный контекст, который я передаю?
Контекст должен быть введен инъекцией зависимости и не должен создаваться вами самостоятельно. Лучше всего создать его как службу с ограниченным объемом посредством внедрения зависимостей. (См. Мой ответ на вопрос 4)
Также подумайте об использовании правильной многоуровневой структуры приложения, такой как «Контроллер»> «Бизнес-логика»> «Репозиторий». В этом случае ваш контроллер получит не db-context, а репозиторий. Внедрение / создание экземпляра db-контекста в контроллере говорит мне, что архитектура вашего приложения совмещает множество обязанностей в одном месте, что - ни при каких обстоятельствах - я не могу рекомендовать.
2. Могу ли я иметь один глобальный контекст, который можно использовать повсюду?
Да, можно , но вопрос должен быть: « Следует ли мне…» -> НЕТ. Контекст предназначен для использования в каждом запросе для изменения вашего репозитория, а затем его снова.
3. Вызывает ли это снижение производительности?
Да, потому что DBContext просто не создан для того, чтобы быть глобальным. Он хранит все данные, которые были введены или запрошены в него, до тех пор, пока он не будет уничтожен. Это означает, что глобальный контекст будет становиться все больше и больше, операции с ним будут становиться все медленнее и медленнее, пока вы не получите исключения из памяти или не умрете от старости, потому что все это замедлилось до ползания.
Вы также получите исключения и множество ошибок, когда несколько потоков одновременно обращаются к одному и тому же контексту.
4. Как все остальные это делают?
DBContext, внедренный фабрикой посредством внедрения зависимостей; сфера действия:
services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
Надеюсь, мои ответы помогут.
источник
Прямо сейчас я пробую этот подход, который позволяет избежать создания экземпляра контекста, когда вы вызываете действия, которые его не используют.
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); } }
источник
GC.GetTotalMemory()
вернулось (не идеально, но это то, что я нашел), и разница никогда не превышала 8 КБ.Это, очевидно, более старый вопрос, но если вы используете 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); } }
источник
Вы должны удалить контекст сразу после каждой операции Save (). В противном случае каждое последующее сохранение займет больше времени. У меня был проект, который создавал и сохранял сложные объекты базы данных в цикле. К моему удивлению, операция стала в три раза быстрее после того, как я переместил "using (var ctx = new MyContext ()) {...}" внутрь цикла.
источник