EF Core Include()涉及多对多关系

ale*_*sio 4 c# entity-framework lazy-loading ef-code-first entity-framework-core

ProductCustomer之间的关系 是多对多的类型(从设计角度来看).

使用EF Core,我们将此关系与第三个实体(ProductCustomer)分成两个一对多关系

public partial class ProductCustomer
{
    public long ProductId { get; set; }
    public long CustomerId { get; set; }   
    public virtual Customer Customer { get; set; }
    public virtual Product Product { get; set; }

    public virtual ICollection<UsageRecord> UsageRecord { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

UsageRecord是一个记录列表,其中包含某个客户在使用产品时使用的数据量

public partial class UsageRecord
{
     public long Id { get; set; }
     public long ProductId { get; set; }
     public long CustomerId { get; set; }           
     public decimal Quantity { get; set; }                
     public virtual ProductCustomer ProductCustomer { get; set; }                
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我尝试读取特定的UsageRecord,则ProductCustomer对象为null(完美,我正在使用急切的加载方法)

return _usageRecordEntity.Where(x => x.ProductId == productId).AsEnumerable();
Run Code Online (Sandbox Code Playgroud)

VS2017  - 调试

但是如果我特别要求Include()ProductCustomer实体,那么实体框架不仅包括所有递归引用,还包括Product对象而不是Customer!

return _usageRecordEntity.Where(x => x.ProductId == productId).Include(p => p.ProductCustomer).AsEnumerable();
Run Code Online (Sandbox Code Playgroud)

vs 2017-debug

第一件事:我不明白为什么它包括整个对象链如果我特别要求ProductCustomer一个.

第二件事:为什么是产品而不是顾客?!


我为完整性包含了Context模型:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Customer>(entity =>
        {
            entity.Property(e => e.customerId)
                .IsRequired()
                .HasColumnName("CustomerId")
                .HasMaxLength(255);
        });

        modelBuilder.Entity<Product>(entity =>
        {
            entity.Property(e => e.Name)
                .IsRequired()
                .HasMaxLength(50);
        });

        modelBuilder.Entity<ProductCustomer>(entity =>
        {
            entity.HasKey(e => new { e.ProductId, e.CustomerId })
                .HasName("PK__ProductCustomerComposite");

            entity.HasOne(d => d.Customer)
                .WithMany(p => p.ProductCustomer)
                .HasForeignKey(d => d.CustomerId)
                .OnDelete(DeleteBehavior.Restrict)
                .HasConstraintName("FK__ProductCu__CustomerId");

            entity.HasOne(d => d.Product)
                .WithMany(p => p.ProductCustomer)
                .HasForeignKey(d => d.ProductId)
                .OnDelete(DeleteBehavior.Restrict)
                .HasConstraintName("FK__ProductCu__ProductId");
        });

        modelBuilder.Entity<UsageRecord>(entity =>
        {
            entity.Property(e => e.Quantity)
                .HasColumnType("decimal")
                .HasDefaultValueSql("0");

            entity.HasOne(d => d.ProductCustomer)
                .WithMany(p => p.UsageRecord)
                .HasForeignKey(d => new { d.ProductId, d.CustomerId })
                .OnDelete(DeleteBehavior.Restrict)
                .HasConstraintName("FK_UsageRecordProductcustomer");
        });
    }
Run Code Online (Sandbox Code Playgroud)

Iva*_*oev 7

基本上,答案是通过以下提供的提示加载相关数据-预先加载的EF核心的部分文档(重点是我的):

实体框架核心将自动将导航属性修复到先前加载到上下文实例中的任何其他实体.因此,即使您没有明确包含导航属性的数据,如果之前加载了部分或全部相关实体,仍可能会填充该属性.