If you look at docs and other docs, you can see that you can access the navigation, but It's pointed out in the docs that this may be changed later. Do not depend on the join type being Dictionary<string, object> unless this has been explicitly configured.
So I'd create a JoinTable by hand, it's not that hard really:
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public List<BookGenre> BookGenres { get; set; }
}
public class Genre
{
public int Id { get; set; }
public string Name { get; set; }
public List<BookGenre> BookGenres { get; set; }
}
public class BookGenre
{
public int GenreId { get; set; }
public int BookId { get; set; }
public Genre Genre { get; set; }
public Book Book { get; set; }
}
If you feel empowered you can add Fluent-api configurations so you depend on EF as little as possible. In the OnModelCreatingMethod in your context or in your separate Configuration file add (optional):
builder.Entity<BookGenre>()
.ToTable("BookGenre")
.HasKey(_ => new { _.BookId, _.GenreId });
builder.Entity<BookGenre>()
.Property(_ => _.BookId)
.ValueGeneratedNever();
builder.Entity<BookGenre>()
.Property(_ => _.GenreId)
.ValueGeneratedNever();
builder.Entity<BookGenre>()
.HasOne(_ => _.Book)
.WithMany(_ => _.BookGenres)
.HasForeignKey(_ => _.BookId);
builder.Entity<BookGenre>()
.HasOne(_ => _.Genre)
.WithMany(_ => _.BookGenres)
.HasForeignKey(_ => _.GenreId);
You also need to add the JoinTable to your Context:
public DbSet<BookGenre> BookGenreRelations { get; set; }
Now you can add new relations:
this.myContext.BookGenreRelations.Add(new BookGenre {
BookId = myBookId,
GenreId = myGenreId,
});
this.myContext.SaveChanges();
Note: In the above examples you can use async versions as well.