Home > Enterprise >  Mapping multiple foreign key/navigation properties to single collection navigation property - is thi
Mapping multiple foreign key/navigation properties to single collection navigation property - is thi

Time:09-05

Consider the following Entity Framework Core 6.0 model classes:

public class Person
{
    public int Id { get; set; }

    [Required]
    public int? PrimaryAddressId { get; set; }
    public Address? PrimaryAddress { get; set; }

    public int? SecondaryAddressId { get; set; }
    public Address? SecondaryAddress { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public List<Person> People { get; set; } = new();
}

From a functionality perspective, I want to be able to load an Address with any and all People related to that Address, and each Person will have at least one primary Address.

Does Entity Framework support mapping multiple foreign key/reference navigation properties in one model class to a single collection navigation property in another? If so, how is that expressed?

CodePudding user response:

You can set it up using multiple collection properties on Address:

public class Person
{
    public int Id { get; set; }

    [Required] 
    public int PrimaryAddressId { get; set; }
    public Address PrimaryAddress { get; set; }

    public int? SecondaryAddressId { get; set; }
    public Address? SecondaryAddress { get; set; }
}

public class Address
{
    public int Id { get; set; }
    public List<Person> PrimaryPeopleAddresses { get; set; } = new();
    public List<Person> SecondaryPeopleAddresses { get; set; } = new();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Person>()
        .HasOne(person => person.PrimaryAddress)
        .WithMany(a => a.PrimaryPeopleAddresses);

    modelBuilder.Entity<Person>()
        .HasOne(person => person.SecondaryAddress)
        .WithMany(a => a.SecondaryPeopleAddresses);
}

Also since primary address is required it should not be marked as nullable.

CodePudding user response:

No, it is not possible to have one navigation collection in one entity (Address.People) which is mapped to multiple navigation properties in the other entity (Person.PrimaryAddress and Person.SecondaryAddress). You can try setting this up in your OnModelCreating() method like this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Address>()
        .HasMany<Person>(p => p.People)
        .WithOne(p => p.PrimaryAddress)
        .HasForeignKey(p => p.PrimaryAddressId);

    modelBuilder
        .Entity<Address>()
        .HasMany<Person>(p => p.People)
        .WithOne(p => p.SecondaryAddress)
        .HasForeignKey(p => p.SecondaryAddressId);
    
    modelBuilder
        .Entity<Person>()
        .HasOne<Address>(p => p.PrimaryAddress)
        .WithMany(p => p.People)
        .HasForeignKey(p => p.PrimaryAddressId);

    modelBuilder
        .Entity<Person>()
        .HasOne<Address>(p =>p.SecondaryAddress)
        .WithMany(p => p.People)
        .HasForeignKey(p => p.SecondaryAddressId);
}

However, this will result in an exception eventually:

System.InvalidOperationException: Cannot create a relationship between 'Address.People' and 'Person.SecondaryAddress' because a relationship already exists between 'Address.People' and 'Person.PrimaryAddress'. Navigations can only participate in a single relationship. If you want to override an existing relationship call 'Ignore' on the navigation 'Person.SecondaryAddress' first in 'OnModelCreating'

  • Related