EF Core Eager加载嵌套集合

Chr*_*ton 5 c# entity-framework-core

我正在尝试在Entity Framework Core中加载相关的模态,但是由于某种原因,当我在Include()调用中没有要求时,正在加载一个嵌套集合。

这是我的两个模型-

Driver.cs

public partial class Driver : IBaseEntity
{
    public short DriverId { get; set; }
    public string Surname { get; set; }
    public string Initials { get; set; }
    public byte DriverStatusTypeId { get; set; }

    public DriverStatusType DriverStatusType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DriverStatusType.cs

public partial class DriverStatusType
{
    public DriverStatusType()
    {
        Drivers = new HashSet<Driver>();
    }

    public byte DriverStatusTypeId { get; set; }
    public string DriverStatusTypeName { get; set; }
    public string Description { get; set; }

    public ICollection<Driver> Drivers { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DriversService.cs

public class DriverService : IDriverService
{
    public DriverService(MyContext context)
    {
        Context = context;
    }

    public MyContext Context { get; }

    public async Task<IEnumerable<Driver>> GetAllDrivers()
    {
        var drivers = await Context
            .Drivers
            .Include(d => d.DriverStatusType)
            .toListAsync();

        return drivers;
    }

    public async Task<Driver> GetDriverById(int id)
    {
        var driver = await Context
            .Drivers
            .Include(d => d.DriverStatusType)
            .Where(d => d.DriverId == id)
            .FirstOrDefaultAsync();

        return driver;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我GetDriverById(int id)从控制器调用该方法时,我会得到期望的结果-

{
    "driverId": 1,
    "surname": "Stark",
    "initials": "T",
    "driverStatusTypeId": 2,
    "driverStatusType": {
        "driverStatusTypeId": 2,
        "driverStatusTypeName": "Available",
        "description": "This driver is available",
        "drivers": []
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,该GetAllDrivers()方法返回的是嵌套drivers集合,这意味着我要返回的数据非常庞大-

[
    {
        "driverId": 1,
        "surname": "Stark",
        "initials": "T",
        "displayText": "Tony Stark",
        "driverStatusTypeId": 2,
        "driverStatusType": {
            "driverStatusTypeId": 2,
            "driverStatusTypeName": "Available",
            "description": "This driver is available",
            "drivers": [
                {
                    "driverId": 2,
                    "surname": "Rogers",
                    "initials": "S",
                    "driverStatusTypeId": 2
                },
                {
                    "driverId": 3,
                    "surname": "Romanoff",
                    "initials": "N",
                    "driverStatusTypeId": 2
                },
                {
                    "driverId": 4,
                    "surname": "Banner",
                    "initials": "B",
                    "driverStatusTypeId": 2
                },
                ...
Run Code Online (Sandbox Code Playgroud)

我以为渴望加载的想法是只包含您在include语句中指定的相关模型,但事实并非如此。有人可以解释这里发生了什么吗?

Iva*_*oev 5

我以为渴望加载的想法是只包含您在include语句中指定的相关模型,但事实并非如此。有人可以解释这里发生了什么吗?

您说得对,事实并非如此。急切加载的想法是确保加载您指定的相关数据。这并不意味着/保证包括相关数据。

EF核心文档的“ 加载相关数据”部分对此进行了部分解释:

小费

实体框架核心将自动将导航属性修复为先前加载到上下文实例中的任何其他实体。因此,即使您未明确包含导航属性的数据,如果先前已加载了某些或所有相关实体,也可能仍会填充该属性。

导航属性修复意味着在任何时候实体实例实例化,所有相关的导航属性都会更新以反映它,例如Driver将其添加到Driver.DriverStatusType.Drivers,反之亦然。

请注意,在使用跟踪查询时,这可能会实现非包含查询(ToList()之后发生因为更改跟踪程序会跟踪对象引用并在执行其他跟踪查询时自动更新它们。

修复过程的另一个效果是,当您包含关系的一端时,另一端的反向导航属性将自动填充。

因此,即使是第一种情况,Drivers也应填充该属性并包含单个项目。这就是我的干净测试中实际发生的事情,不知道您为什么会有所不同-可能是序列化程序隐藏了它?

无论如何,所有这些都意味着您无法真正控制导航属性的内容。您可以精确控制返回的唯一方法是使用特殊的DTO / ViewModel等类和投影(Select)。