26

How do you use the Fluent API to create a many to many relationship between two tables in EF7 EF Core? For example, say you have the following tables:

Photos to People database diagram

How would one leverage the modelBuilder in the DbContext class to define a relationship like this?

I've seen this link from the EF team's meeting notes regarding this subject, but it is from last year and am wondering if there is new information on how to approach this in EF7 EF Core.

I am able to create one to many relationships between Photos and PhotosPeople as well as People and PhotosPeople. The database is generated as I'd like it to be, but the navigation between People and Photos now requires interaction with an intermediate entity. I'd like to avoid this.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Paul
  • 1,590
  • 5
  • 20
  • 41

1 Answers1

48

This is tracked by #1368. The workaround is to map the join table to an entity:

class Photo
{
    public int Id { get; set; }
    public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}

class PersonPhoto
{
    public int PhotoId { get; set; }
    public Photo Photo { get; set; }

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

class Person
{
    public int Id { get; set; }
    public ICollection<PersonPhoto> PersonPhotos{ get; set; }
}

Be sure to configure PersonPhoto with a composite key:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonPhoto>().HasKey(x => new { x.PhotoId, x.PersonId });
}

To navigate, use a Select:

// person.Photos
var photos = person.PersonPhotos.Select(c => c.Photo);
Matt Flowers
  • 800
  • 9
  • 12
bricelam
  • 28,825
  • 9
  • 92
  • 117
  • 1
    When I try to run the migration it says: Microsoft.Data.Entity.Metadata.ModelItemNotFoundException: The entity type 'PersonPhoto' requires a key to be defined. – Olle Jun 17 '15 at 18:53
  • 3
    Hence my note in the code. Configure it using `modelBuilder.Entity().Key(x => new { x.PhotoId, x.PersonId });` – bricelam Jun 18 '15 at 15:22
  • 1
    Ohh. Great. Thanks bricelam. Sorry for not paying attention. Thanks. – Olle Jun 18 '15 at 19:29
  • 2
    @bricelam, I'm having some trouble in Asp.Net 5 when trying this approach, following your exmaple, apparently if I try to return a JSON of a Person with her Photos I got no response because it falls in a forever loop of references between Person, and the PersonPhotos collection, have any way to solve this situation? – Rafael Miceli Oct 26 '15 at 14:49
  • @bricelam this approach worked fine for me when I'm adding the entity, but I had to write all the logic for adding and removing the rows on the join table while updating. Is there an easiest way to update? Thanks in advance – mgalindez Nov 01 '15 at 16:45
  • @bricelam, I am using EF7. I tried to follow your example and created a composite key, but it returned me an error - EntityTypeBuilder does not contain a definition for 'Key' or extension method 'Key'. Did it require any other reference? – seanbun Nov 16 '15 at 12:33
  • 7
    @seanbun I believed the method was renamed to `HasKey` (to match EF6) – bricelam Nov 16 '15 at 18:07
  • Let's say you have a person and you want to assign a list of photos to the person. How do you go about this? – Riscie Feb 23 '17 at 10:31
  • @Riscie See the [Relationships](https://learn.microsoft.com/en-us/ef/core/modeling/relationships) article in the EFCore documentation for other types of relationships. – bricelam Feb 23 '17 at 16:33
  • @bricelam I have a many-to-many relationship like described here. I don't understand how I can make multiple connections between the two entities at once. Like when I have a `Person` and a list of `Photos` (like in the example above), how can I create the mapping-entities of type `PersonPhoto` all at once? – Riscie Feb 23 '17 at 17:09
  • @Riscie Ah, I see. You'll need two association classes. (e.g. `PersonTaggedInPhoto` and `PersonLikesPhoto`) – bricelam Feb 23 '17 at 21:13