Entity Framework Core can't resolve inverse properties even with annotation

c# entity-framework entity-framework-6 entity-framework-core

Question

I've reduced this to a rather simple use case:

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; }
}

Running the migration will result in:

System.InvalidOperationException: Unable to determine the relationship represented by navigation property 'ItemRental.OriginatingSalesOrder' of type 'SalesOrder'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

With EF 6.x, this identical connection works just fine. I'm sure the Fluent API might help me with this, but I'd want to learn how to use annotations instead.

Here is a comparable query that I located: Relationship problem with the EntityFramework core model during add-migration But it doesn't make this issue go away.

EDIT: Here is a sample answer: https://drive.google.com/file/d/0BzgvtZfXt8MHd1RseVJubmd6TEU/view?usp=sharing

1
0
10/15/2017 2:28:34 AM

Accepted Answer

Because your data annotations are entirely legitimate, there is nothing to comprehend in this situation.

The root of the problem is a simpler one: a regression defect in EF Core 2.0 that is being monitored by open issue #9180 Metadata: When using KeyAttribute on PK, InverseProperty cannot resolve ambiguity. in the EFC issue tracker and slated for the next 2.1 release.

Fluent API is the proposed solution in the link until then, however it also works if you deleteKey from attributeSalesOrderId housing inSalesOrder (because it fortunately adheres to one of the accepted PK protocols)

public class SalesOrder
{    
    public Int32 SalesOrderId { get; set; }    
    // ...
}

, or if you use theInverseProperty attribute on the navigation characteristics of a collection:

public class ItemRental
{
    // ...
    [ForeignKey("OriginatingSalesOrderId")]
    [InverseProperty("Rentals")]
    public SalesOrder OriginatingSalesOrder { get; set; } 
    // ...    
    [ForeignKey("DepositCreditedOnSalesOrderId")]
    [InverseProperty("Refunds")]
    public SalesOrder DepositCreditedOnSalesOrder { get; set; }
}
5
10/15/2017 11:07:43 AM

Popular Answer

Ivan is entirely right.

I used the following easy method to get around the problem (you don't need to rename a column with this approach):

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; }
    }


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow