Недавно я начал изучать Entity Framework Core, и мне любопытно, можно ли использовать экземпляр DbContext внутри класса сущности.
Образец кода:
class User {
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Order> Orders { get; set; }
public void LoadOrders() {
using (var context = new StoreContext()) {
Orders = context.Orders
.Where(x => x.UserId == Id)
.ToList();
}
}
}
Сущность пользователя связана с классом Order, у обоих из них есть соответствующие таблицы в базе данных, созданные с помощью миграции из Entity Framework. Цель метода LoadOrders () - просто загрузить связанные сущности для текущего пользователя, когда это необходимо.
Теперь я хотел узнать, верен ли это подход?
Или, может быть, мне всегда следует загружать связанные объекты одновременно с загрузкой родительского объекта? (Например, .Include (). ThenInclude ())
Или, может быть, код метода LoadOrders () должен быть расположен в каком-то дополнительном классе, таком как UserHelper, который будет использоваться вместе с сущностью User.
Должно быть действительным. Проблема создания структуры базы данных и чтения / записи в базу данных - это две отдельные проблемы, и их следует рассматривать как таковые для более слабосвязанной конструкции. Если вы хотите протестировать свой код, я бы также предложил вам использовать какой-либо шаблон проектирования, например, на мгновение шаблон репозитория.
На самом деле дизайн, ориентированный на предметную область, рекомендует делать что-то подобное, чтобы избежать «анемичных занятий». Вместо создания экземпляра DbContext попробуйте передать его методу. Загляните в эту статью. thereformedprogrammer.net/…





Вам следует избегать использования подобного подхода, потому что пользователь будет загружен одним контекстом DbContext, а его заказы будут связаны с другим удаленным контекстом. Когда вы перейдете к обновлению пользователя, вы столкнетесь с ошибками или дублирующимися заказами, или у вас возникнет беспорядочный бизнес по повторной привязке заказа (и других дочерних сущностей) к контекстам перед сохранением. В дальнейшем, несомненно, возникнет путаница, если заказы привязаны к пользователям, и кто-то пойдет и напишет код в .Include(x => x.Orders). Если вы полностью отсоедините связанные сущности от EF и полагаетесь на нагрузку по запросу, вы потеряете большую часть возможностей, которые дает вам EF. .
Подобные проблемы обычно возникают из-за смешения объема / продолжительности жизни сущностей и контекста, из которого они загружаются. Например, загрузка сущностей одним методом с помощью DbContext, их возврат, а затем решение о том, что вы хотите получить доступ к связанным сущностям, но DbContext был удален. Самый простой метод, который я могу порекомендовать, - это использование моделей представления POCO и обеспечение того, чтобы объекты никогда не выходили из области действия своего DbContext, а только модели представления. Таким образом, вы можете создать структуру модели представления для представления необходимых данных, а затем использовать сущности и их ссылки для заполнения этих моделей представления с помощью .Select(), не беспокоясь о ленивой загрузке или нетерпеливой загрузке.
Например:
using (var context = new StoreContext())
{
var userViewModel = context.Users.Where(x => x.UserId == userId)
.Select(x => new UserViewModel
{
UserId = x.UserId,
UserName = x.UserName,
Orders = x.Orders
.Where(o => o.IsActive)
.Select( o => new OrderViewModel
{
OrderId = o.OrderId,
OrderNumber = o.OrderNumber
Price = o.OrderItems.Sum(i => i.Price)
}).ToList()
}).SingleOrDefault();
return userViewModel;
}
Automapper может помочь с отображением объектов для просмотра моделей. Это не однозначная карта древовидной структуры, а скорее выравнивание модели представления для представления данных, необходимых представлению, с последующим заполнением их структурой сущности. Вам просто нужно быть немного осторожным, чтобы извлекать только данные и поддерживаемые агрегированные методы из сущностей, потому что они будут переданы в SQL, поэтому никаких .Net или пользовательских функций в .Select. Позвольте моделям представления принимать необработанные значения и предоставлять альтернативные свойства для выполнения форматирования или использовать .Select() для выборки анонимных типов, заставить EF материализовать их в экземпляры POCO с помощью .ToList() / .Single() / и т. д. а затем заполните свои модели представлений из тех, которые используют Linq2Object.
Работа с объектами по запросу и просмотр моделей / DTO для передачи данных позволяет избежать множества проблем с объектами. Если все сделано правильно, EF может извлекать эти данные очень быстро и позволяет избежать проблем с производительностью, таких как отключение ленивых нагрузок во время сериализации. Это означает, что когда вы закончите с моделью представления, вам нужно будет повторно загрузить объект, чтобы применить изменения. Может показаться, что имеет больше смысла просто использовать объекты, а затем EF волшебным образом повторно присоединить их и сохранить изменения, но ваша модель представления будет иметь всю информацию, необходимую для быстрого получения этого объекта по идентификатору, если это необходимо, и вам нужно будет рассмотреть случаи где данные могли измениться между моментом, когда вы впервые получили объект, и временем, когда вы готовы его изменить.
Думаю, лучший вариант - использовать его в клиентском коде.