0

In my ASP.Net Core 3.1 app I want to define a Facility and a Person model where each facility can have one representative and many delegates of the type Person but I'm getting the "Unable to determine the relationship represented by navigation property 'Facility.Delegates' of type 'List'" error.

public class Facility
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Activity { get; set; }

    public int RepresentativeId { get; set; }
    public Person Representative { get; set; }

    public List<Person> Delegates { get; set; }
}
public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }

    [InverseProperty("Representative")]
    public List<Facility> RepresentedFacilities { get; set; }
    [InverseProperty("Delegates")]
    public List<Facility> DelegatedToFacilities { get; set; }
}

How to properly accomplish this mapping? Are there better solutions to my problem?

my MDB
  • 129
  • 1
  • 2
  • 10
  • That's a many-to-many relationship, you need to follow https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key#many-to-many – Camilo Terevinto Dec 25 '20 at 14:59
  • Does this answer your question? [How to fix 'Unable to determine the relationship represented by navigation property' error in Entity Framework](https://stackoverflow.com/questions/55629131/how-to-fix-unable-to-determine-the-relationship-represented-by-navigation-prope) – Majid Shahabfar Dec 26 '20 at 15:42
  • It's many to many only if one person can be delegate to many facilities. Is that the case? – Gert Arnold Dec 26 '20 at 22:32

2 Answers2

1
public class Facility
{  
    ...//other properties
    public List<Person> Delegates { get; set; }
}

public class Person
{ 
    ...//other properties
    [InverseProperty("Representative")]
    public List<Facility> RepresentedFacilities { get; set; }
    [InverseProperty("Delegates")]
    public List<Facility> DelegatedToFacilities { get; set; }
}

In previous versions of Entity Framework, this model definition (using the above code) was sufficient for EF to imply the correct type of relationship and to generate the join table for it. In EF Core up to and including 3.x, it is necessary to include an entity in the model to represent the join table, and then add navigation properties to either side of the many-to-many relations that point to the join entity instead. So, try to modify your code as below:

public class Facility
{
    [Key]
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    public string Activity { get; set; }
    public int RepresentativeId { get; set; }
    public Person Representative { get; set; }
    public List<PersonFacilities> PersonFacilities { get; set; }
}

public class Person
{
    [Key]
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
    [InverseProperty("Representative")]
    public List<PersonFacilities> RepresentedFacilities { get; set; }
    [InverseProperty("Delegates")]
    public List<PersonFacilities> DelegatedToFacilities { get; set; }
}

public class PersonFacilities
{
    //public int PersonId { get; set; }
    //public Person Person { get; set; } 
    public int FacilityId { get; set; }
    public Facility Facility { get; set; }

    public int RepresentactivePersonId { get; set; }
    public Person Representative { get; set; }
    public int DelegatePersonId { get; set; }
    public Person Delegates { get; set; }
}

The join table will be named after the join entity by convention. The relationship also needs to be configured via the Fluent API for EF Core to be able to map it successfully:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<PersonFacilities>().HasKey(pf => new { pf.FacilityId, pf.DelegatePersonId, pf.RepresentactivePersonId });
        modelBuilder.Entity<PersonFacilities>()
            .HasOne(pf => pf.Representative).WithMany(p => p.RepresentedFacilities)
            .HasForeignKey(pf => pf.RepresentactivePersonId).OnDelete(DeleteBehavior.Restrict);
        modelBuilder.Entity<PersonFacilities>().HasOne(pf => pf.Delegates).WithMany(p => p.DelegatedToFacilities)
            .HasForeignKey(pf => pf.DelegatePersonId).OnDelete(DeleteBehavior.Restrict); 
        modelBuilder.Entity<PersonFacilities>().HasOne(pf => pf.Facility).WithMany(p => p.PersonFacilities)
            .HasForeignKey(pf => pf.FacilityId).OnDelete(DeleteBehavior.Restrict);
    }

Then, after migration, the result like this:

enter image description here

Reference:

Configuring Many To Many Relationships in Entity Framework Core

The InverseProperty Attribute

Zhi Lv
  • 18,845
  • 1
  • 19
  • 30
0

To get many-to-many relationships you need to add a class FacilityPerson:

[Keyless]
public class FacilityPerson
{
    public int PersonId { get; set; }
    public Person Person { get; set; }
    public int FacilityId { get; set; }
    public Facility Facility{ get; set; }
  
}
Serge
  • 40,935
  • 4
  • 18
  • 45