Этот ответ конкретно относится к проблеме, упомянутой в вопросе об использовании загруженных объектов в представлении ASP.NET.Вопрос касается способа решения этой проблемы без блока using
или утилизации DbContext
, однако я предлагаю сделать именно это.
Причина в том, что обычно желательно не использовать объекты Entity Framework в представлениях ASP.NET, потому что эти объекты намного больше, чем просто объекты POCO;они скрывают логику, которая позволяет им выступать в качестве прокси-сервера для базовой базы данных, поэтому у них есть скрытая зависимость от состояния DbContext
, которое их создало.
Вот надуманный пример использования моделей EF для Employee
и Department
с DbContext
:
public class CompanyDbContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
public class Department
{
public long Id { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public long Id { get; set; }
public long DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
Если бы они использовались в приложении ASP.NET, я бы создалнекоторые отдельные модели, которые не привязаны к Entity Framework, для использования в ASP.NET.Например:
public class DepartmentModel
{
public long Id { get; set; }
public List<EmployeeModel> Employees { get; set; }
}
public class EmployeeModel
{
public long Id { get; set; }
public long DepartmentId { get; set; }
}
Несколько соображений:
Согласно документам MSDN, "A DbContext
представляет собой комбинацию UnitOfWork и репозиторияпаттерны " - https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view=entity-framework-6.2.0 - Поэтому DbContext
должно быть как можно более коротким.
При загрузке данных из контекста связанные объекты могут быть извлечены с использованием DbSet<>.Include()
- https://docs.microsoft.com/en-us/ef/ef6/querying/related-data
Вообще говоря, имеет смысл определитьсоедините слой «data» со слоем «view» - по разным причинам, некоторые из которых перечислены здесь: https://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5 - это включает отображение между объектами EF и моделями POCO.
Логика, которая используется для запроса DbContext
, будет запрашивать данные с использованием EF и возвращать эти данные с использованием моделей POCO, так что только логика, имеющая непосредственное отношение к DbContext
, имеетучастие в объектах EF.Например:
public List<DepartmentModel> GetAllDepartments()
{
using (var ctx = new CompanyDbContext())
{
// Ensure that related data is loaded
var departments = ctx.Departments
.Include(d => d.Employees);
// Manual mapping by converting into a new set of models to be used by the Views
var models = departments
.Select(d => new DepartmentModel
{
Id = d.Id,
Employees = d.Employees
.Select(e => new EmployeeModel
{
Id = e.Id,
DepartmentId = e.DepartmentId
})
.ToList(),
})
.ToList();
return models;
}
}
Возможность использовать эти модели POCO, требуя некоторого дополнительного стандартного кода, обеспечивает полное разделение между DbContext
и ASP.NET, позволяя использовать данные без ASP.NET.Представления / контроллеры, связанные с временем жизни или состоянием DbContext
.
Иногда это может выглядеть так, как если бы этот подход нарушал принцип «СУХОГО», однако я хотел бы отметить, что объекты EF и объекты ViewModel существуют для решения разных проблем, и весьма часто объекты ViewModel принимают разныеформировать или даже требовать дополнительных полей / атрибутов, которые не подходят для добавления в классы EF.
Наконец, вышеупомянутое использует «ручное» отображение, но если отображения действительно просты и понятны, тоВместо этого может иметь смысл использовать AutoMapper: Самый чистый способ привязать объект к DTO с помощью Linq Select?