Two One-to-Many relationships in the same table

别说谁变了你拦得住时间么 提交于 2019-12-04 13:10:42

Have you tried decorating the collection properties with the InverseProperty attribute?

[InverseProperty( "MasterAccount" )]
public virtual List<SystemAccount> AllSubAccounts { get; set; }

[InverseProperty( "SecondMasterAccount" )]
public virtual List<SystemAccount> SecondarySubAccounts { get; set; }

Here's a demo that works for me:

public class HierarchicalEntity
{
    public int Id { get; set; }
    public string Description { get; set; }

    [ForeignKey( "PrimaryParent" )]
    public int? PrimaryParentId { get; set; }

    [ForeignKey( "SecondaryParent" )]
    public int? SecondaryParentId { get; set; }
    public virtual HierarchicalEntity PrimaryParent { get; set; }

    public virtual HierarchicalEntity SecondaryParent { get; set;}

    [InverseProperty( "PrimaryParent" )]
    public ICollection<HierarchicalEntity> ChildrenViaPrimaryParent { get; set; }

    [InverseProperty( "SecondaryParent" )]
    public ICollection<HierarchicalEntity> ChildrenViaSecondaryParent { get; set; }
}

I have reproduced the problem now with EF 5. I get exactly the same exception and stack trace and also the exception in your EDIT 2 when applying Moho's code. The problem does not occur with EF 6. So, if upgrading to EF 6 is an option for you that would solve the problem.

If you need to stick with EF 5 using Fluent API mapping instead of using the [InverseProperty] attribute worked for me without exceptions. You can remove all attributes then:

public class SystemAccount
{
    public int ID { get; set; }

    public int? MasterAccountID { get; set; }
    public int? SecondMasterAccountID { get; set; }

    public virtual SystemAccount MasterAccount { get; set; }
    public virtual SystemAccount SecondMasterAccount { get; set; }

    public virtual List<SystemAccount> AllSubAccounts { get; set; }
    public virtual List<SystemAccount> SecondarySubAccounts { get; set; }
}

Relationship mapping with Fluent API:

modelBuilder.Entity<SystemAccount>()
    .HasOptional(s => s.MasterAccount)
    .WithMany(s => s.AllSubAccounts)
    .HasForeignKey(s => s.MasterAccountID);

modelBuilder.Entity<SystemAccount>()
    .HasOptional(s => s.SecondMasterAccount)
    .WithMany(s => s.SecondarySubAccounts)
    .HasForeignKey(s => s.SecondMasterAccountID);

The fact that the [InverseProperty] attribute with your model causes exceptions appears to be a bug in EF 5. The bug is most likely related to the self-referencing kind of the relationships because normally with relationships between different entities the attribute works without problems.

My solution is based on the advice I got from @Slauma and @Moho (+1 to both of you for your help!).

It is true that the [InverseProperty] attribute is what was missing, but it wouldn't work when I just put it on the file. Then, when I tried @Moho's code in a completely new file, it still didn't work. So I switched the [ForeignKey] attributes from being on the ID fields to being on the object fields themselves, i.e.:

public int? PrimaryParentId { get; set; }
public int? SecondaryParentId { get; set; }

[ForeignKey( "PrimaryParent" )]
public virtual HierarchicalEntity PrimaryParent { get; set; }

[ForeignKey( "SecondaryParent" )]
public virtual HierarchicalEntity SecondaryParent { get; set;}

That ended up working. But when I tried doing that on my SystemAccount class it wouldn't work. So I ended up doing the following steps to get it to work:

  1. Commented out the list objects, as well as the parent records, and the FK attribute from both fields.
  2. Migrated the database. All FKs now dropped.
  3. Uncommented it out
  4. Checked that the [InverseProperty] attribute was on the list objects, and put the [ForeignKey] attribute on the virtual objects.
  5. Migrated the database. The only FKs that show up are the ones that I want to be FKs!

I know that it's a weird solution, but as long as it works...

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