DetachedLazyLoadingWarning 的 Entity Framework Core 2.1 问题

Posted

技术标签:

【中文标题】DetachedLazyLoadingWarning 的 Entity Framework Core 2.1 问题【英文标题】:Entity Framework Core 2.1 problem with DetachedLazyLoadingWarning 【发布时间】:2019-04-13 23:25:14 【问题描述】:

DetachedLazyLoadingWarning 出现异常:

为警告“Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning”生成错误:尝试在“DeliveryProxy”类型的分离实体上延迟加载导航属性“Product”。分离实体或使用“AsNoTracking()”加载的实体不支持延迟加载。通过将事件 ID 'CoreEventId.DetachedLazyLoadingWarning' 传递给 'DbContext.OnConfiguring' 或 'AddDbContext' 中的 'ConfigureWarnings' 方法,可以抑制或记录此异常。

在尝试使用 Entity Framework Code 2.1

查询 SQL 数据库时

这是我的查询:

var orders = 
    _context
    .Set<Order>()
    .Where(v => v.CompanyId == companyId)
    .Include(v => v.Details)
    .ThenInclude(d => d.Delivery)
    .ThenInclude(v => v.Product)
    .OrderByDescending(v=> v.Details.FirstOrDefault().Delivery.Product.ProductId)
    .ThenByDescending(v=> v.Details.FirstOrDefault().Delivery.Value)
    .ThenByDescending(v => v.CreatedAt)
    .Page(request.Page, request.RowsPerPage);

以下是实体和关系:

public class Order : IEntity<int>

    public int CompanyId  get; set; 

    public virtual ICollection<OrderDetails> Details  get; set; 

    [Required]
    public DateTimeOffset CreatedAt  get; set; 

    [Key]
    public int Id  get; set; 


public class OrderDetails : IEntity<int>

    public int OrderId  get; set; 

    public int DeliveryId  get; set; 

    [ForeignKey(nameof(OrderId))]
    public virtual Order Order  get; set; 

    [ForeignKey(nameof(DeliveryId))]
    public virtual Delivery Delivery  get; set; 

    [Key]
    public int Id  get; set; 


public class Delivery : IEntity<int>

    [Required]
    public int ProductId  get; set; 

    public int Value  get; set; 

    [ForeignKey(nameof(ProductId))]
    public virtual Product Product  get; set; 

    [Key]
    public int Id  get; set; 


[Table("Products")]
public class Product : IEntity<int>

    [Required]
    public byte ProductCategoryId  get; set; 


    public virtual ICollection<Delivery> Deliveries  get; set; 

    [Key]
    public int Id  get; set; 

看起来 Details.FirstOrDefault() 分离实体 Delivery。相同的解决方案适用于 Entity Framework 6。如何改进我的查询以仅使用一个查询从数据库中获取日期(抑制警告没有帮助)?

【问题讨论】:

【参考方案1】:

您还应该看到很多Client evaluation logging 警告。目前客户端评估在显式/延迟加载时效果不佳。

在这种情况下,客户端评估的原因是排序方法中的v.Details.FirstOrDefault() 表达式。 EF Core 当前阶段的挑战是找到支持的可翻译等效 LINQ 构造。

在这种特殊情况下,解决方案(解决方法)是使用中间SelectMany 投影和Take(1)。将.OrderByDescending(..)Page(...) 的部分替换为以下内容:

.SelectMany(
    o => o.Details.Select(d => d.Delivery).Take(1).DefaultIfEmpty(),
    (o, d) => new  Order = o, Delivery = d )
.OrderByDescending(v => v.Delivery.ProductId)
.ThenByDescending(v => v.Delivery.Value)
.ThenByDescending(v => v.Order.CreatedAt)
.Select(v => v.Order) // restore the original projection

【讨论】:

以上是关于DetachedLazyLoadingWarning 的 Entity Framework Core 2.1 问题的主要内容,如果未能解决你的问题,请参考以下文章