EF Core DDD Many-to-many
Asked Answered
G

1

6

I'm trying to follow DDD using EF Core and in my model I have the following:

    private List<TeamPerson> _personLinks;
    
    public IReadOnlyCollection<TeamPerson> PersonLinks => _personLinks?.ToList().AsReadOnly();

    public IReadOnlyCollection<Person> Members => _personLinks?.Select(l => l.Person).ToList().AsReadOnly();

I want to encapsulate the relationship between Team and Person models. I must say right away that there is a mapping for the Person model and it works.

But if I specify property access mode:

builder.HasMany(e => e.PersonLinks)
   .WithOne(e => e.Team)
   .HasForeignKey(e => e.TeamId)
   .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);

builder.HasMany(e => e.TeamLinks)
   .WithOne(e => e.Person)
   .HasForeignKey(e => e.PersonId)
   .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);

And if I try to get dbContext.Teams.Include(t => t.PersonLinks).ThenInclude(t => t.Person), I'm getting an error: "...PersonId1 column doesn't exist...", I have this for TeamPerson model mapping:

builder.Property(e => e.PersonId).IsRequired().HasColumnName("person_id");

What is my mistake or is there any other way to reach the encapsulation for the collection here?

Glossitis answered 30/7, 2020 at 3:24 Comment(1)
DDD has nothing to do with this question, just saying...Goddess
T
0

I think you need to configure a one-to-many relationship between both Person and PersonLinks as well between Team and PersonLinks to achieve the many-to-many relationship.

builder.Entity<PersonLink>()
    .HasKey(personLink => new { personLink.TeamId, personLink.PersonId });

builder.Entity<PersonLink>()
    .HasOne<Team>(personLink => personLink.Team)
    .WithMany(team => team.PersonLinks)
    .HasForeignKey(personLink => personLink.TeamId);

builder.Entity<PersonLink>()
    .HasOne<Person>(personLink => personLink.Person)
    .WithMany(person => person.PersonLinks)
    .HasForeignKey(personLink => personLink.PersonId);

This of course will only work if your PersonLink class looks something like this:

public class PersonLink
{
    public int PersonId { get; set; }
    public Person Person { get; set; }

    public int TeamId { get; set; }
    public Team Team { get; set; }
}

For the id data types I assumed a simple int which could be string or GUID (or even some custom type in your code) but I think this is not that important here.

Note: I could not resist to rename PersonLinks to PersonLink it feels more natural to me because the class represents one person link between Team and Person from my point-of-view. Also, I know it somehow a convention to use abbreviated parameter names for lambda expressions but I think, especially in this case, it is easier to read instead of using p (for Person) and pl (for PersonLink) - maybe it's just a matter of taste in this case...

Tenedos answered 3/8, 2020 at 20:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.