user9124444
user9124444

Reputation:

Direct and Indirec many-to-many configuration using EF Core 5 using

I have the following entities

public class Course
{
    public long Id { get; set; }
    public virtual ICollection<User> Users{ get; set; }
    public virtual ICollection<UserCourse> CourseUsers { get; set; }
}

public class User
{
    public long Id { get; set; }
    public virtual ICollection<Course> Courses { get; set; }
    public virtual ICollection<UserCourse> UserCourses { get; set; }
}

public class UserCourse
{
    public long UserId { get; set; }
    public User User { get; set; }

    public long CourseId { get; set; }
    public Course Course { get; set; }

    public bool IsRequired { get; set; }
}

with the following mappings for

UserCourse mapping :

        builder
            .HasOne(nav => nav.User)
            .WithMany(self => self.UserCourses)
            .HasForeignKey(fk => fk.UserId)
            .OnDelete(DeleteBehavior.Cascade);

        builder
            .HasOne(nav => nav.Course)
            .WithMany(self => self.CourseUsers)
            .HasForeignKey(fk => fk.CourseId)
            .OnDelete(DeleteBehavior.Cascade);

and the User mapping

        builder
            .HasMany(nav => nav.Courses)
            .WithMany(nav => nav.Users);

When trying to create a new migration I'm not exactly sure why I'm getting this.

Cannot use table 'UserCourse' for entity type 'UserCourse' since it is being used for entity type 'UserCourse(Dictionary<string, object>)' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'UserCourse' on the primary key properties and pointing to the primary key on another entity typed mapped to 'UserCourse'.

I understand what the error is, but not sure how to force the UserCourse mapping to use the User mapping generated join table or vice-versa

Also, I need the direcat mapping for OData, and the indirect mapping using the join entity to conduct operations on DbSet<UserCourse>

Upvotes: 0

Views: 376

Answers (1)

Anton Kovachev
Anton Kovachev

Reputation: 347

The public virtual ICollection<User> Users{ get; set; } in Course entity and the the public virtual ICollection<Course> Courses { get; set; } in Users entity are redundant. The entities should look more like this

public class Course
{
   public long Id { get; set; }
   public virtual ICollection<UserCourse> UserCourses { get; set; }
}

public class User
{
   public long Id { get; set; }
   public virtual ICollection<UserCourse> UserCourses { get; set; }
}

public class UserCourse
{
    public long UserId { get; set; }
    public User User { get; set; }

    public long CourseId { get; set; }
    public Course Course { get; set; }

}

And the OnModelCreating method should have this code

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<UserCourse>()
               .HasKey(uc => new { uc.UserId, uc.CourseId }); 

   modelBuilder.Entity<UserCourse>()
               .HasOne(uc => uc.Course)
               .WithMany(c => c.Users)
               .HasForeignKey(uc => uc.CourseId); 

   modelBuilder.Entity<UserCourse>()
               .HasOne(uc => uc.User)
               .WithMany(c => c.Courses)
               .HasForeignKey(uc => uc.UserId);  

    }

If you use EF core 5 you can directly skip the join table. It will be generated and handled by EF behind the scenes. More on the topic here https://www.thereformedprogrammer.net/updating-many-to-many-relationships-in-ef-core-5-and-above/

Upvotes: 1

Related Questions