ashilon
ashilon

Reputation: 1941

EF6 code first Many to Many with additional property of the same type as the collection on one of the entities

I know this issue has many similar questions here on SO, but I couldn't find one that's exactly like mine, but I might be wrong and there exists one. So here's my question:
We have two entities (C# poco classes), Meeting and User, that each one of them contains a collection of the other entity. Code, shortened for brevity:

public class Meeting
{
    public int ModeratorId { get; set; }
    public virtual User Moderator { get; set; }    // Property of type User

    public virtual ICollection<User> Participants { get; set; } // Collection of User
}

And here's the second one:

public class User
{
    public virtual ICollection<Meeting> Meetings { get; set; }
}  

Now, when adding a migration, one would expect that EF would create a linking table, something like MeetingUsers, which it actually creates if I omit the Moderator property. But when I add the Moderator property, that is the same type as the items in Participants, EF removes the linking table and adds a Meeting_Id column in the migration. Here are the migrations:
first migration, with only the collections on the two classes, without the additional Moderator property on Meeting:

public override void Up()
    {   
        CreateTable(
            "dbo.MeetingUsers",
            c => new
                {
                    Meeting_Id = c.String(nullable: false, maxLength: 128),
                    User_ID = c.Int(nullable: false),
                })
            .PrimaryKey(t => new { t.Meeting_Id, t.User_ID })
            .ForeignKey("dbo.Meetings", t => t.Meeting_Id, cascadeDelete: true)
            .ForeignKey("dbo.Users", t => t.User_ID, cascadeDelete: true)
            .Index(t => t.Meeting_Id)
            .Index(t => t.User_ID);
        
    }  

You can see that EF creates the linking table just fine (I omitted the Meeting and User for brevity).
And here's the second migration EF adds after I add the Moderator property:

public override void Up()
    {
        DropForeignKey("dbo.MeetingUsers", "Meeting_Id", "dbo.Meetings");
        DropForeignKey("dbo.MeetingUsers", "User_ID", "dbo.Users");
        DropIndex("dbo.MeetingUsers", new[] { "Meeting_Id" });
        DropIndex("dbo.MeetingUsers", new[] { "User_ID" });
        AddColumn("dbo.Users", "Meeting_Id", c => c.String(maxLength: 128));
        AddColumn("dbo.Meetings", "ModeratorId", c => c.Int());
        AddColumn("dbo.Meetings", "User_ID", c => c.Int());
        CreateIndex("dbo.Users", "Meeting_Id");
        CreateIndex("dbo.Meetings", "ModeratorId");
        CreateIndex("dbo.Meetings", "User_ID");
        AddForeignKey("dbo.Meetings", "ModeratorId", "dbo.Users", "ID");
        AddForeignKey("dbo.Users", "Meeting_Id", "dbo.Meetings", "Id");
        AddForeignKey("dbo.Meetings", "User_ID", "dbo.Users", "ID");
        DropTable("dbo.MeetingUsers");
    }  

As you see EF removed the linking table and adds a column on the Users table, which is not what I want. I want instead to keep the linking table and just add a new column ModeratorId to the Meetings table.
How do I achieve that? I might add that we use data annotations throughout and not the fluent api of EF.

Thanks,
ashilon

Upvotes: 0

Views: 51

Answers (1)

Sadullah DOĞAN
Sadullah DOĞAN

Reputation: 335

You can define manually link table and you are good to go .

 public class Meeting
 {
    public int ModeratorId { get; set; }
    public virtual User Moderator { get; set; }    // Property of type User


}

And here's the second one:  

public class User
{
    .....
} 
public MeetingUser{

   public int UserId{get;set;}
   public virtual User User{get;set;}
   public int MeetingId {get;set;}
   public virtual Meeting Meeting {get;set;}
}

Upvotes: 1

Related Questions