24

I am trying to map many-to-many relationship with the same entity. The User entity has an IList<User> data field for Contacts, which stores users' contacts/friends information:

public class User : DomainModel
{
    public virtual IList<User> Contacts { get; protected set; }
    //irrelevant code omitted
}

When I try to use fluent API to map this many to many relationship, it gives me some trouble. Apparently, when I use HasMany() on the user.Contacts property, it has no WithMany() method to call next. The intellisense from Visual Studio only shows WithOne(), but not WithMany().

modelBuilder.Entity<User>().HasMany(u => u.Contacts).WithMany() 
// gives compile time error: CS1061 'CollectionNavigationBuilder<User, User>' does not contain a definition for 'WithMany' and no extension method 'WithMany' accepting a first argument of type 

So why does this happen? Is there anything I did wrong to map this many-to-many relationship?

user3071284
  • 6,955
  • 6
  • 43
  • 57
Lord Yggdrasill
  • 3,197
  • 4
  • 26
  • 42

1 Answers1

27

So why does this happen? Is there anything I did wrong to map this many-to-many relationship?

No, you didn't do anything wrong. It's just not supported. Current status here.

Many-to-many relationships without an entity class to represent the join table are not yet supported. However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.

With EF-Core you should create the entity for the mapping table. Such as UserContacts. A complete example in the docs, as mentioned in the comments. I haven't actually tested the code below, but it should look something like this:

public class UserContacts
{
    public int UserId { get; set; } 
    public virtual User User { get; set; }

    public int ContactId { get; set; } // In lack of better name.
    public virtual User Contact { get; set; }
}

public class User : DomainModel
{
    public List<UserContacts> Contacts { get; set; }
}

And your modelBuilder.

  modelBuilder.Entity<UserContacts>()
        .HasOne(pt => pt.Contact)
        .WithMany(p => p.Contacts)
        .HasForeignKey(pt => pt.ContactId);

    modelBuilder.Entity<UserContacts>()
        .HasOne(pt => pt.User)
        .WithMany(t => t.Contacts)
        .HasForeignKey(pt => pt.UserId);
smoksnes
  • 10,509
  • 4
  • 49
  • 74
  • 1
    In the first modelBulder.Entity, should it be ".WithMany(p => p.Users)" instead of ".WithMany(p => p.Contacts)"? – Carlos Feb 25 '17 at 13:21
  • @CarlosAdrián - I think not. Since its a reference to the same table. It is still a user which has several contacts. The contact is still a user. – smoksnes Feb 25 '17 at 13:35
  • 3
    This solution did not work for me. Instead I found the following answer to a similar question that solved the many-to-many self-reference problem for me: https://stackoverflow.com/a/49219124/430742 – Jpsy Apr 27 '18 at 07:12
  • @Jpsy Yes you are correct. Existing answer was not correct. Existing answer would only works for the many to many between two different types not for the same type. I have modified the answer. Now it will work for the same type. – TanvirArjel Aug 15 '18 at 06:20
  • 1
    @TanvirArjel: Sorry, I don't see your edit yet. Did you save your changes correctly? Currently the last edit of this answer is from Feb 25'17. – Jpsy Aug 16 '18 at 07:42
  • @Jpsy smoksnes didn't approve my modification to his answer. I have posted it as a separate answer. Please check it. – TanvirArjel Aug 16 '18 at 08:03