EF Core Eager加载嵌套集合

时间:2018-11-26 09:36:41

标签: 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; }
}

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; }
}

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;
    }
}

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

{
    "driverId": 1,
    "surname": "Stark",
    "initials": "T",
    "driverStatusTypeId": 2,
    "driverStatusType": {
        "driverStatusTypeId": 2,
        "driverStatusTypeName": "Available",
        "description": "This driver is available",
        "drivers": []
    }
}

但是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
                },
                ...

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

1 个答案:

答案 0 :(得分:4)

  

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

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

在EF Core文档的Loading Related Data部分中进行了部分解释:

  

提示

     

Entity Framework Core将自动将导航属性修复为先前加载到上下文实例中的任何其他实体。因此,即使您未明确包含导航属性的数据,如果先前已加载了部分或全部相关实体,该属性仍可能被填充。

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

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

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

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

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