Использование экземпляра DbContext внутри класса сущности - PullRequest
0 голосов
/ 02 октября 2018

Недавно я начал изучать 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.

1 Ответ

0 голосов
/ 03 октября 2018

Вам следует избегать использования такого подхода, поскольку пользователь будет загружен одним 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, поэтому в .Select нет .Net или пользовательских функций.Пусть модели представлений принимают необработанные значения и предоставляют альтернативные свойства для выполнения форматирования или используют .Select() для извлечения анонимных типов, заставляют EF материализовать их в экземпляры POCO с помощью .ToList() / .Single() / и т. Д.а затем заполните свои модели представлений теми, которые используют Linq2Object.

Работа с объектами по требованию и просмотр моделей / DTO для перемещения данных позволяет избежать проблем с объектами.Если все сделано правильно, EF может извлечь эти данные очень быстро и избежать ошибок, связанных с производительностью, таких как отключение из-за отложенных нагрузок во время сериализации.Это означает, что когда вы закончите работу с моделью представления, вам потребуется перезагрузить объект, чтобы применить изменения.Может показаться, что имеет больше смысла просто использовать сущности, а затем EF волшебным образом присоединить их и сохранить изменения, но ваша модель представления будет иметь всю информацию, необходимую для быстрого извлечения этой сущности по ID, если это необходимо, и вам нужно будет рассмотреть случаигде данные могли измениться между временем, когда вы впервые получили объект, и временем, когда вы готовы его изменить.

...