EF Core ThenInclude检索所有嵌套数据

时间:2019-09-12 06:41:11

标签: c# entity-framework entity-framework-core

我有多个相关对象,这些对象通过API以JSON格式公开:

{
    "name": "Building 1",
    "country": {
      "text": "USA",
      "value": 2,
      "states": [
        {
          "text": "Alabama",
          "value": 2,
          "cities": []
        },
        {
          "text": "Alaska",
          "value": 4,
          "cities": []
        },
        {
          "text": "Arizona",
          "value": 7,
          "cities": []
        },
        {
          "text": "Arkansas",
          "value": 11,
          "cities": []
        }
      ]
    },
    "id": 4
  }

构建表的列为"CountryId""StateId""CityId"

下面的代码应该根据关系明确地将建筑物带入国家,州和城市。

_dbContext.Buildings.Include(o => o.Country).ThenInclude(s => s.States).ThenInclude(c => c.Cities).ToListAsync();

执行查询后,国家实体会带出甚至与该特定建筑物都不相关的每个国家。

所需结果如下:

{
    "name": "Building 1",
    "country": {
      "text": "USA",
      "value": 2,
      "states": [
        {
          "text": "Alabama",
          "value": 2,
          "cities": []
        }
      ]
    },
    "id": 4
  }

ThenInclude查询是否可能存在问题,或者存在任何其他解决方案?

感激。

2 个答案:

答案 0 :(得分:1)

如果要求建筑物拥有一个州,那么就不需要一个可以通过州检索的国家。同时拥有State和Country可以很容易导致数据状态不一致,例如,如果初始状态显示为State = California,Country = USA,则某些系统可以在不更改状态的情况下将Country更改为指向“加拿大”,或更改状态而无需更改国家,结果为Building.State.Country <> Building.Country。如果建筑物需要城市,则可以从城市推断出州和国家。拥有多个FK会使结构异常规范,并容易导致不一致。

对于问题的根源,实体应始终反映完整的数据状态,而不是您可能希望向视图呈现的已过滤状态。如果您直接为建筑物指定了国家/地区,则序列化国家/地区将包含该国家/地区的所有引用国家,因为这反映了国家/地区是什么。您不想要国家/地区,而只想要具有适用于该建筑物且格式特定的州和城市的国家/地区数据。

这是视图模型或DTO的责任,因此可以利用投影将实体转变为要传递回视图/消费者的结构:

[Serializable]
public class BuildingViewModel
{
   public string Name { get; set; }
   public BuildingCountryViewModel Country { get; set; }
}

[Serializable]
public class BuildingCountryViewModel
{
   public string Text { get; set; }
   public int Value { get; set; }
   public BuildingStateViewModel State { get; set; }
}

[Serializable]
public class BuildingStateViewModel
{
   public string Text { get; set; }
   public int Value { get; set; }
   public BuildingCityViewModel City { get; set; }
}

[Serializable]
public class BuildingCityViewModel
{
   public string Text { get; set; }
}

然后...

var building = context.Buildings.Where(x => x.Name == "Building 1")
   .Select(x => new BuildingViewModel
   {
      Name = x.Name,
      Country = x.City.State.Country.Select(c => new BuildingCountryViewModel
      {
          Text = c.Text,
          Value = c.Value,
          State = x.City.State.Select(s => new BuildingStateViewModel
          {
             Text = s.Text,
             Value = s.Value,
             City = x.City.Select(ci => new BuildingCityViewModel
             {
                Text = ci.Text
             }
          }
       }
    }).Single();

实体反映了完整的数据状态,因此,如果建筑物必须属于某个城市,那么我们就不必仅仅因为可能要以其他格式显示它就对其进行非规范化。 (国家->州->城市)上面的示例假定需要城市,并将仅在建筑物上具有城市参考的城市=>州=>国家关系插入到视图模型将显示的位置。

答案 1 :(得分:-1)

尝试:

_dbContext.Buildings.Include(c => c.Cities).ThenInclude(s => s.States).ThenInclude(o => o.Country).ToListAsync();