Reputation:
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
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