我把它归结为一个非常小的用例:
public class ItemRental
{
[Key]
public Int32 ItemRentalId { get; set; }
public Int32? OriginatingSalesOrderId { get; set; }
[ForeignKey("OriginatingSalesOrderId")]
public SalesOrder OriginatingSalesOrder { get; set; }
public Int32? DepositCreditedOnSalesOrderId { get; set; }
[ForeignKey("DepositCreditedOnSalesOrderId")]
public SalesOrder DepositCreditedOnSalesOrder { get; set; }
}
public class SalesOrder
{
[Key]
public Int32 SalesOrderId { get; set; }
[InverseProperty("OriginatingSalesOrder")]
public ICollection<ItemRental> Rentals { get; set; }
[InverseProperty("DepositCreditedOnSalesOrder")]
public ICollection<ItemRental> Refunds { get; set; }
}
public class MyAppDatabase : DbContext
{
public MyAppDatabase(DbContextOptions<MyAppDatabase> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
base.OnModelCreating(modelBuilder);
}
public DbSet<ItemRental> ItemRentals { get; set; }
public DbSet<SalesOrder> SalesOrders { get; set; }
}
尝试运行迁移将提供:
System.InvalidOperationException:无法确定导航属性&#39; ItemRental.OriginatingSalesOrder&#39;表示的关系。类型&#39; SalesOrder&#39;。手动配置关系,或使用&#39; [NotMapped]&#39;忽略此属性。属性或使用&#39; EntityTypeBuilder.Ignore&#39;在&#39; OnModelCreating&#39;。
对于EF 6.x,这种关系完全没问题。我相信我可以使用Fluent API解决这个问题,但我更愿意了解如何使用注释来完成这项工作。
我在这里找到了一个类似的问题:EntityFramework core model relationship issue while doing Add-Migration但它并没有解决这个问题。
编辑:示例解决方案:https://drive.google.com/file/d/0BzgvtZfXt8MHd1RseVJubmd6TEU/view?usp=sharing
答案 0 :(得分:5)
这里没有什么可以理解的,因为您的数据注释是完全有效的。
问题的原因更为简单 - 在EFC问题跟踪器中由#9180 Metadata: InverseProperty fails to resolve ambiguity while use KeyAttribute on PK未解决的问题跟踪的EF Core 2.0(回归)错误,计划在下一个2.1版本中发布。
在此之前,链接中建议的解决方法是使用流畅的API,但如果您从Key
中的SalesOrderId
属性中删除SalesOrder
属性,它也可以使用(因为它很幸运地遵循公认的PK公约之一):
public class SalesOrder
{
public Int32 SalesOrderId { get; set; }
// ...
}
或者如果您对集合导航属性应用InverseProperty
属性:
public class ItemRental
{
// ...
[ForeignKey("OriginatingSalesOrderId")]
[InverseProperty("Rentals")]
public SalesOrder OriginatingSalesOrder { get; set; }
// ...
[ForeignKey("DepositCreditedOnSalesOrderId")]
[InverseProperty("Refunds")]
public SalesOrder DepositCreditedOnSalesOrder { get; set; }
}
答案 1 :(得分:0)
伊万是完全正确的。
我使用下一个简单的方法来避免这个问题(通过这种方式你不需要重命名一个列):
public class ItemRental
{
[Column("ItemRentalId")] //new
public Int32 Id { get; set; } //new
public Int32? OriginatingSalesOrderId { get; set; }
[ForeignKey("OriginatingSalesOrderId")]
public SalesOrder OriginatingSalesOrder { get; set; }
public Int32? DepositCreditedOnSalesOrderId { get; set; }
[ForeignKey("DepositCreditedOnSalesOrderId")]
public SalesOrder DepositCreditedOnSalesOrder { get; set; }
}
public class SalesOrder
{
[Column("SalesOrderId")] //new
public Int32 Id { get; set; } //new
[InverseProperty("OriginatingSalesOrder")]
public ICollection<ItemRental> Rentals { get; set; }
[InverseProperty("DepositCreditedOnSalesOrder")]
public ICollection<ItemRental> Refunds { get; set; }
}
public class MyAppDatabase : DbContext
{
public MyAppDatabase(DbContextOptions<MyAppDatabase> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(x => x.GetForeignKeys()))
{
relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
base.OnModelCreating(modelBuilder);
}
public DbSet<ItemRental> ItemRentals { get; set; }
public DbSet<SalesOrder> SalesOrders { get; set; }
}