Ho ridotto questo a un caso d'uso piuttosto minimale:
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; }
}
Cercare di eseguire la migrazione darà:
System.InvalidOperationException: impossibile determinare la relazione rappresentata dalla proprietà di navigazione "ItemRental.OriginatingSalesOrder" di tipo "SalesOrder". Configurare manualmente la relazione o ignorare questa proprietà utilizzando l'attributo "[NotMapped]" o utilizzando "EntityTypeBuilder.Ignore" in "OnModelCreating".
Questa stessa relazione è perfettamente soddisfacente con EF 6.x. Sono sicuro di poterlo risolvere utilizzando l'API Fluent, ma preferirei capire come farlo funzionare usando le annotazioni.
Ho trovato una domanda simile qui: Problema di relazione del modello core di EntityFramework mentre si fa Add-Migration Ma non risolve questo problema.
MODIFICA: soluzione di esempio qui: https://drive.google.com/file/d/0BzgvtZfXt8MHd1RseVJubmd6TEU/view?usp=sharing
Non c'è niente da capire qui perché le annotazioni dei dati sono perfettamente valide.
La causa del problema è più banale: bug di EF Core 2.0 (regressione) tracciato da # 9180 Metadata: InverseProperty non riesce a risolvere l'ambiguità mentre si usa KeyAttribute sul problema PK open in EFC tracker, in programma per la prossima versione 2.1.
Fino ad allora, la soluzione suggerita nel collegamento è quello di utilizzare API fluente, ma anche funziona se si rimuove Key
attributo dal SalesOrderId
proprietà a SalesOrder
(poiché segue per fortuna quello delle convenzioni PK riconosciuti):
public class SalesOrder
{
public Int32 SalesOrderId { get; set; }
// ...
}
oppure se si applica l'attributo InverseProperty
nelle proprietà di navigazione della raccolta:
public class ItemRental
{
// ...
[ForeignKey("OriginatingSalesOrderId")]
[InverseProperty("Rentals")]
public SalesOrder OriginatingSalesOrder { get; set; }
// ...
[ForeignKey("DepositCreditedOnSalesOrderId")]
[InverseProperty("Refunds")]
public SalesOrder DepositCreditedOnSalesOrder { get; set; }
}
Ivan è completamente corretto.
Ho usato il prossimo modo semplice per evitare il problema (in questo modo non è necessario rinominare una colonna):
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; }
}