【问题标题】:ASP.NET Core Web API can not return results extracted using EF Core lazy-loadingASP.NET Core Web API 无法返回使用 EF Core 延迟加载提取的结果
【发布时间】:2021-09-09 12:13:38
【问题描述】:

我正在探索 EF Core 延迟加载,但很难通过 ASP.NET Web API 返回结果。请在下面查看我的 API 调用。

// GET: api/Supplier
[HttpGet("/GetSupplierUsingLazyLoading")]
public async Task<ActionResult<Supplier>> GetSupplierUsingLazyLoading()
{
    var products = _context.Products.ToList();
    var supplier = products.Last().Supplier;

    return await Task.FromResult(supplier);
    //return await Task.FromResult(new Supplier());
}

是的。我已经添加了包Microsoft.EntityFrameworkCore.Proxies

我在我的Startup.cs 中添加了UseLazyLoadingProxies

services.AddDbContext<NorthwindContext>(
        options =>
        {
            options.UseMySql(Configuration.GetConnectionString("Northwind_MySQL"), Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.23-mysql"));
            options.UseLazyLoadingProxies();
            options.LogTo(Console.WriteLine, LogLevel.Information);
        }
    );

我使用Pomelo.EntityFrameworkCore.MySql 作为数据库提供者。

当我从 swagger 调用 Web API 时,它会在后台进行大量数据库调用。这是我在终端中看到的。它一直在打这些电话。我不得不停止应用程序来停止这些调用。我不确定我在这里做错了什么。还有其他人面临这个问题吗?

info: 6/26/2021 08:01:55.859 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) 
      Executed DbCommand (1ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT `o`.`OrderDetailsID`, `o`.`Discount`, `o`.`OrderID`, `o`.`ProductID`, `o`.`Quantity`, `o`.`UnitPrice`
      FROM `orderdetails` AS `o`
      WHERE `o`.`OrderID` = @__p_0
info: 6/26/2021 08:01:55.863 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (0ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT `o`.`OrderDetailsID`, `o`.`Discount`, `o`.`OrderID`, `o`.`ProductID`, `o`.`Quantity`, `o`.`UnitPrice`
      FROM `orderdetails` AS `o`
      WHERE `o`.`OrderID` = @__p_0
info: 6/26/2021 08:01:55.867 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (0ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT `o`.`OrderDetailsID`, `o`.`Discount`, `o`.`OrderID`, `o`.`ProductID`, `o`.`Quantity`, `o`.`UnitPrice`
      FROM `orderdetails` AS `o`
      WHERE `o`.`OrderID` = @__p_0
info: 6/26/2021 08:01:55.870 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (0ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT `o`.`OrderDetailsID`, `o`.`Discount`, `o`.`OrderID`, `o`.`ProductID`, `o`.`Quantity`, `o`.`UnitPrice`
      FROM `orderdetails` AS `o`
      WHERE `o`.`OrderID` = @__p_0
info: 6/26/2021 08:01:55.876 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command) 
      Executed DbCommand (1ms) [Parameters=[@__p_0='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT `o`.`OrderDetailsID`, `o`.`Discount`, `o`.`OrderID`, `o`.`ProductID`, `o`.`Quantity`, `o`.`UnitPrice`
      FROM `orderdetails` AS `o`
      WHERE `o`.`OrderID` = @__p_0

当我使用return await Task.FromResult(new Supplier()); 时,它返回一个空的供应商。

谢谢 好奇的驱动器

【问题讨论】:

  • 尝试手动或使用映射器(如 AutoMapper)将实体映射到普通对象,以在将结果返回给客户端之前强制获取关系。即使用 DTO
  • 无关:你可以简单的在异步函数中返回结果,或者return Task.FromResult(val),你不需要await Task.FromResult(val)
  • 有趣...我尝试访问供应商的属性之一(即公司名称)并将其返回到另一个对象中并且它有效。似乎它无法返回虚拟财产本身。在返回之前我必须将它复制到一些东西中?
  • 是的,在它尝试从数据库中查询数据之前,您必须尝试访问它。
  • 嗯....那是一个曲线球。无论如何,感谢您的评论。它现在正在工作。

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


【解决方案1】:

首先:请记住,延迟加载是一项仅在需要时才从数据库中检索数据的功能,应谨慎使用。

考虑到这一点,让我们谈谈您的模型。 假设您有一个Supplier。该供应商必须与Orders 联系,因为您总是从供应商那里购买东西,对吗?所有Orders 都有OrderItems,并且每个项目都与Product 相关。所以我们以这样的模型图结束:

你的类应该是这样的

public class Supplier
{
    public string Name { get; set; }
    List<Order> Orders { get; set; }
}

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}

public  class OrderItem
{
    public int OrderItemId { get; set; }
    public int ProductId { get; set; }
    public Product Product { get; set; }

    public int OrderId { get; set; }
    public Order Order { get; set; }
}

public class Order 
{
    public decimal FinalPrice { get; set; }
    public int SupplierId { get; set; }
    public Supplier Supplier { get; set; }
    List<OrderItem> OrderItems { get; set; }
}

当您尝试序列化来自数据库的供应商时,它还将序列化其Orders,然后是OrderItems,最后是Product,因为您的完整对象图已序列化。

还记得只有在需要时才从数据库中检索数据吗?好吧,序列化程序一次序列化每个节点,所以如果你有 4 个订单项,它会向数据库询问这 4 个产品 4 次。

当您序列化 new Supplier() 时,这不会发生,原因有两个。 new Supplier() 未被 EntityFramework 跟踪,因此不会进行任何查询,即使被跟踪,此供应商也没有订单,因此不会运行其他查询。

【讨论】:

  • 感谢您的详细解答。 Microsoft 文档应该这么详细。
  • 不客气,伙计!延迟加载 + EntityFramework 的工作原理有时会很棘手。
猜你喜欢
  • 1970-01-01
  • 2019-03-12
  • 1970-01-01
  • 2019-08-05
  • 2016-10-10
  • 1970-01-01
  • 2019-03-26
  • 1970-01-01
  • 2021-01-31
相关资源
最近更新 更多