EF在复合主键的一部分上一对多

EF one to many on part of composite primary key

我在现有数据库中有三层表,我试图在获取中间层数据时包括底层记录...这应该是一对多关系 - 对于 shipment x 和 product y有z个分析结果

public class Shipment
{
   [Key]
   public int Id { get; set; } 
   public string ShipName { get; set; }
   public DateTime ShipmentDate { get; set; }
}

public class ShipmentDetails
{
   [ForeignKey ("ShipmentId")]
   public int Id { get; set; } 
   [ForeignKey ("ProductId")]
   public int ProductId { get; set; }
   Public double Weight { get; set; }
   public virtual ShippingAnalysis Analysis { get; set; }
}

public class ShipmentAnalysis
{
   [ForeignKey ("ShipmentId")]
   public int Id { get; set; } 
   [ForeignKey ("ProductId")]
   public int TenantId { get; set; }
   [ForeignKey ("MetricId")]
   public int MetricId { get; set; }
   Public double Result { get; set; }
}

我正在使用流畅的 api 定义复合主键的方式。

modelBuilder.Entity<ShippingDetail>()
            .HasKey(c => new { c.ShipmentId, c.ProductlId });

modelBuilder.Entity<ShippingAnalysis>()
            .HasKey(c => new { c.ShipmentId, c.ProductId, c.MetricId });

我通过(一对多)分析记录获取运输详细信息。

var results = _context.ShippingDetail.Include(sd => sd.Analysis)
                                     .Where(sd => sd.ShipmentId == id);

这不是 return 邮递员的结果,而是通过浏览器 return 格式错误的 JSON。如果我删除包含,它工作正常。

问题不在于复合键,而在于导航属性(因此关系定义)。在(一)侧(如果存在)的导航 属性 必须是 集合 ,在(多)侧的导航 属性 应该是 reference - 参见 Relationships - Definition of Terms

根据

modelBuilder.Entity<ShippingDetail>()
    .HasKey(c => new { c.ShipmentId, c.ProductlId });

modelBuilder.Entity<ShippingAnalysis>()
    .HasKey(c => new { c.ShipmentId, c.ProductId, c.MetricId });

关系应该是ShippingDetail(一)->(多)ShippingAnalysis,因此

public virtual ShippingAnalysis Analysis { get; set; }
ShippingDetail

属性 必须是

public virtual ICollection<ShippingAnalysis> Analysis { get; set; }

这应该足以让 EF Core 确定正确的复合 FK 列。但是,如果您想百分百确定(明确无误),请添加以下流畅的配置:

modelBuilder.Entity<ShippingDetail>()
    .HasMany(e => e.Analysis)
    .WithOne() // make sure to specify navigation property if exists, e.g. e => e.NavProp
    .HasForeignKey(e => new { e.ShipmentId, e.ProductId });

P.S。删除所有这些 [ForeignKey] 数据注释。它们根据是应用于 FK 属性 还是导航 属性 来做不同的事情,并且肯定不会按照你的想法去做,有时实际上可能会导致意想不到的行为。根据我在 EF Core 关系方面的经验,要么让 EF Core 约定发挥作用,要么使用流畅的 API.