ASP.NET Core API仅返回列表的第一个结果

35
我已创建了一个团队 Web API 控制器,并尝试调用 GET 方法获取数据库中所有团队的 JSON 结果。但是当我进行调用时,只能获取到第一个团队的 JSON,但在返回语句上设置断点时,它包括了所有 254 支球队以及所有比赛信息。
这是我正在处理的两个模型:
public class Team
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Icon { get; set; }
    public string Mascot { get; set; }
    public string Conference { get; set; }
    public int NationalRank { get; set; }

    public List<Game> Games { get; set; }
}

public class Game
{
    public string Id { get; set; }
    public string Opponent { get; set; }
    public string OpponentLogo { get; set; }
    public string GameDate { get; set; }
    public string GameTime { get; set; }
    public string TvNetwork { get; set; }
    public string TeamId { get; set; }

    public Team Team { get; set; }
}

当我这样做时:
[HttpGet]
public async Task<List<Team>> Get()
{
    var teams = await _context.Teams.ToListAsync();

    return teams;
}

我得到了所有的254个团队,但是由于EF Core不支持延迟加载,所以Game属性为空。因此我真正想做的是添加.Include(),像这样:

[HttpGet]
public async Task<List<Team>> Get()
{
    var teams = await _context.Teams.Include(t => t.Games).ToListAsync();

    return teams;
}

这将返回第一支球队和第一场比赛,但没有其他信息。以下是json格式:
[
  {
    "id": "007b4f09-d4da-4040-be3a-8e45fc0a572b",
    "name": "New Mexico",
    "icon": "lobos.jpg",
    "mascot": "New Mexico Lobos",
    "conference": "MW - Mountain",
    "nationalRank": null,
    "games": [
      {
        "id": "1198e6b1-e8ab-48ab-a63f-e86421126361",
        "opponent": "vs Air Force*",
        "opponentLogo": "falcons.jpg",
        "gameDate": "Sat, Oct 15",
        "gameTime": "TBD ",
        "tvNetwork": null,
        "teamId": "007b4f09-d4da-4040-be3a-8e45fc0a572b"
      }
    ]
  }
]

当我在return语句上设置断点时,显示有254个团队,每个团队的比赛都被正确填充了...但是json结果并没有反映出来。下面是一张图片:
enter image description here
我已经尝试过同步和异步两种方式,但得到的结果相同。您知道为什么我只能在json中获得一个结果,而在断点处却有所有结果吗?

我尝试了您的代码,但使用了我可用的Users表,在这两种情况下都可以工作... var teams = await _context.Users.Include(u => u.Roles).ToListAsync(); 它只是序列化JSON中的所有项目... :( - Gerardo Grignoli
@GerardoGrignoli 真的吗? 你在使用Entity Framework Core还是Entity Framework 6? - Aaron
我正在使用EF Core。 - Gerardo Grignoli
2
你尝试过 services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); 吗? - adem caglin
你能试着将循环标记为[JsonIgnore]吗? [JsonIgnore] public Team Team { get; set; } - Gerardo Grignoli
@ademcaglin,这个方法可行!谢谢你。请将它发布为答案,我会接受它。 - Aaron
2个回答

54

1
非常感谢。这让我抓狂了。 - user906573
6
最令人沮丧的Bug - blagae

1
值得注意的是,如果您像使用内联 JsonSerializerSettings 选项一样控制 json 输出,那么这是值得注意的。
[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
    var teams = await _context.Teams.Include(t => t.Games).ToListAsync();

    return Json(teams, new JsonSerializerSettings() { 
         NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include
    });
}

仅仅采用@adeam-caglin建议的解决方案并不足够,你还需要在返回值中设置相应的设置。例如:

[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
    var teams = await _context.Teams.Include(t => t.Games).ToListAsync();

    return Json(teams, new JsonSerializerSettings() { 
         NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include,
         ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });
}

基本上它会将你在Startup.cs中设置的内容置空,而不是添加。这也为你提供了一条路线,可以逐个案例地进行输出,而不是全局修改。

编辑

我想花点时间澄清当你使用ReferenceLoopHandling.Ignore时会发生什么,你是在请求从喷火龙头中饮水,但希望它是有控制的流量。如果你有一个高度开发的模型,你很可能会有一个集合,你认为你要得到你预期的实体及其子列表,但如果那些列表项也有子项或其他父项,那么你将会加载这些内容。假设你有

Teams>Players>Contacts
Games>Teams

这将产生一个嵌套的JSON返回结果。我本想得到一个平坦的Game>Teams,但最终却是Games>Teams>Players。这只是一个简单的例子,但很容易看出如何从几KB的数据转换为永无止境的循环,使消费结果的客户端发生故障。
这意味着你需要自己控制流程。要获得预期的更平的JSON返回结果,您还需要在.Include(x => x.Games)上使用.AsNoTracking()
作为一个非常简单的例子,您需要执行以下操作:
[HttpGet]
public async Task<IActionResult> Get([FromForm]bool strip_nulls = true)
{
    var teams = _context.Teams.AsQueryable();
    teams = teams.Include(t => t.Games).AsNoTracking();
    Teams _return = await teams.ToListAsync();
    return Json(_return, new JsonSerializerSettings() { 
         NullValueHandling = strip_nulls ? NullValueHandling.Ignore : NullValueHandling.Include,
         ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接