Define relationships for hierarchical data in Entity Framework Code First

旧巷老猫 提交于 2019-12-06 12:37:30

Just a few ideas:

  • Your mapping with data annotations doesn't work because EF Code First conventions don't recognize which navigation properties belong together. Obviously you want to associate Bill.RelatedBills with BillRelation.Bill. But because there is a second navigation property BillRelation.RelatedBill refering to the Bill entity as well the AssociationInverseDiscoveryConvention can't be applied to recognize the correct relation. This convention only works if you have exactly one pair of navigation properties on the entities. As a consequence, EF assumes actually three relationships, each with only one exposed end in the model. The relationship where Bill.RelatedBills belongs to assumes a not exposed foreign key on the other side according to EF default naming conventions - which is Bill_ID with underscore. It doesn't exist in the database, hence the exception.

  • In your Fluent API mapping I would just try to remove ...ToTable(...) altogether. I believe that it is not necessary as the mapping knows anyway which table the foreign key belongs to. This will possibly fix the second error ("Table ... does not exist....")

  • Your second mapping - the one-to-one relationship - does possibly not work as expected because one-to-one relationships are "usually" mapped with a shared primary key association between the tables in the database. (I am not sure though if shared primary keys are really required by EF.) Because your BillId column seems to be a foreign key which is not a primary key at the same time I would try to map the relationship as one-to-many. Moreover because your foreign key columns are exposed as properties in the model you should use HasForeignKey instead of MapKey:

    modelBuilder.Entity<Bill>()
        .HasMany( b => b.RelatedBills )
        .WithRequired( r => r.Bill )
        .HasForeignKey ( r => r.BillID );
    // turn off/on cascade delete by chaining
    //  .WillCascadeOnDelete(true/false)
    // here at the end
    
    modelBuilder.Entity<BillRelation>()
        .HasRequired( r => r.RelatedBill )
        .WithMany()
        .HasForeignKey ( r => r.RelatedBillID );
    // turn off/on cascade delete by chaining
    //  .WillCascadeOnDelete(true/false)
    // here at the end
    

Edit

It is possible that the whole Fluent mapping is not necessary if you put the [InverseProperty] attribute on one of the navigation properties - for example in your Bill class:

[InverseProperty("Bill")]
public virtual ICollection<BillRelation> RelatedBills { get; set; }

In this attribute you specify the name of the associated navigation property on the related entity. This binds Bill.RelatedBills and BillRelation.Bill together to a pair of navigation properties being the ends of the same association. I hope that EF will do the correct thing with the remaining navigation property BillRelation.RelatedBill, i.e. create a one-to-many relationship - I hope... If the default cascading delete won't work for you, you are forced to use Fluent API though since there is no data annotation attribute to configure cascading delete.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!