【问题标题】:How to return nested tables (one-to-many) in .NET Core WebAPI using Entity Framework Core?如何使用 Entity Framework Core 在 .NET Core WebAPI 中返回嵌套表(一对多)?
【发布时间】:2020-11-13 15:25:44
【问题描述】:

我是 .NET 的新手,无法弄清楚为什么我会得到某些结果。我发现了一些急切与延迟加载的结果,但没有一个解决方案有效。

我已经更改了列和数据的名称,因为它与工作相关,所以没有可用的公共 repo。

目前我的前端正在接收如下形状的数据:

{
    id: 234,
    column1: 1,
    column2: 2,
    column3: null
}

我希望它在嵌套数组中返回一对多关系,如下所示:

{
    id: 234,
    column1: 1,
    column2: 2,
    column3: [
        {
            table2Column1: 1,
            table2Column2: 2,
            table2Column3: 3,
        },
        {
            table2Column1: 7,
            table2Column2: 8,
            table2Column3: 9,
        },
    ]
}

以下是我的模型和控制器模式:

// Table1.cs

...
public int Id { get; set; }
public int Column1 { get; set; }
public int Column2 { get; set; }
public ICollection<Table2> Column3 { get; set; }
...

// Table2.cs
...
public int Id { get; set; }
public int Table2Column1 { get; set; }
public int Table2Column2 { get; set; }
public int Table2Column3 { get; set; }

public int Table1Id { get; set; }
public Table1 Table1 { get; set; }
...

//Table1Controller.cs
...
// GET: api/table1/{id}
[HttpGet("{id}")]
public Task<ActionResult<Table1>> GeTable1ById(int id)
{
    return await _context.Table1.FindAsync(id);
}
...

我发现信息说必须使用 Include 语句来强制加载,所以我将控制器更改为:

//Table1Controller.cs
...
// GET: api/table1/{id}
[HttpGet("{id}")]
public ActionResult<Table1> GeTable1ById(int id)
{
    return _context.Table1
                      .Include("Table2")
                      .Where(p => p.Id == id);
}
...

我尝试了一些变化,但错误的要点是我改变了数据的形状,所以它不适合模型......虽然它应该是因为它应该从链接表中预测 ICollection。 EFCore 在创建迁移和更新数据时很好用,因为在 SQLServer 中使用外键一切正常。

返回的错误是:error CS0029: Cannot implicitly convert the type 'System.Linq.IQueryable&lt;Project.Models.Table1&gt;' to 'Microsoft.AspNetCore.Mvc.ActionResult&lt;Project.Models.Table1&gt;'

我如何急切地加载表并将其连接到完整的记录中? 感谢您的帮助。



已解决

Sergey 的原始答案有效,但在前端循环引用失败(EFCore 要求)。所以你必须告诉 Json 序列化器忽略向后引用。工作代码如下:

// Table2.cs 使用 System.Text.Json; 使用 System.Text.Json.Serializer; ... 公共 int ID { 获取;放; } 公共 int Table2Column1 { 获取;放; } 公共 int Table2Column2 { 获取;放; } 公共 int Table2Column3 { 获取;放; }

public int Table1Id { get; set; }
[JsonIgnore]
public Table1 Table1 { get; set; }
...

//Table1Controller.cs
...
// GET: api/table1/{id}
[HttpGet("{id}")]
public ActionResult<Table1> GeTable1ById(int id)
{
    return _context.Table1
                      .Include("Table2")
                      .Where(p => p.Id == id)
                      .FirstOrDefault();
}
...

【问题讨论】:

    标签: c# .net .net-core asp.net-web-api entity-framework-core


    【解决方案1】:

    将您的操作更改为:

    HttpGet("{id}")]
    public ActionResult<Table1> GeTable1ById(int id)
    {
      
    return _context.Table1
                          .Include(t=>t.Column3)
                          .Where(p => p.Id == id)
                          .FirstOrDefault();
    

    【讨论】:

    • 这让我可以构建,但是现在调用 API 会触发错误 System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This is either due to a cycle or if the object depth is larger than the maximum depth of 32 这是因为我的 Table2 有对​​ Table1 的引用吗? EFCore 文档说这是必要的。
    • 得到了答案,您的原始答案有效,然后为避免循环引用,您必须在向后引用上使用 [JsonIgnore] 属性更新 Table2。非常感谢您的帮助。
    • 感谢您的反馈。
    【解决方案2】:

    您必须包含导航属性,而不是包含表名。此查询应该有效:

    var query =  _context.Table1
                    .Include(t1 => t1.Column3)
                    .Where(p => p.Id == id);
    

    【讨论】:

    • 这不会改变错误。我不认为问题出在查询返回的数据上,我认为这与数据的形状和预期的返回类型有关
    猜你喜欢
    • 2023-03-12
    • 2020-03-23
    • 2022-01-09
    • 2020-06-30
    • 2021-05-11
    • 2022-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多