.net core ef core Fluent API c#

Configuring Many To Many Relationships in Entity Framework Core

Matt 2020/03/13 01:07:18
60

A many-to-many relationship occurs between an entity work one-to-many to another. It's a typical scenario for db develop. Take an example, we want build a blog, a post can appear in many categories and a category can also contain many posts. This form of relationship is represented in a database by a join table (aka bridging, junction or linking table).

Generally, the join table contains just the entity key values of each side of the relationship. In the posts and categories example, there will be in a field named by PostId and the other for the CategoryId.

A many-to-many relationship is defined in code by the inclusion of collection properties in each of the entities, The Categories property in the Post class, and the Posts property in the Category class:

/// <summary>
/// a Post entity
/// </summary>
public class Post
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    [MaxLength(200)]
    public string Title { get; set; }
    [MaxLength(200)]
    public string Slug { get; set; }
    [MaxLength(1000)]
    public string Description { get; set; }
    public string Content { get; set; }
    [MaxLength(100)]
    public string Author { get; set; }
    public DateTime CreatedTime { get; set; }

    public virtual ICollection<PostCategoryJoinTable> PostCategories { get; set; }
}

/// <summary>
/// a Category entity
/// </summary>
public class Category
{
    [Key]
    public int Id { get; set; }
    [Required]
    [MaxLength(100)]
    public string Name { get; set; }

    public virtual ICollection<PostCategoryJoinTable> PostCategories { get; set; }
}

In previous versions of Entity Framework, this model definition above was enough for EF to implement the correct type of relationship (many-to-many) and to generate the join table automatically. In EF Core, the model to represent the join table is created by manual, and then add navigation properties to either side of the many-to-many relations that point to the join entity instead:

/// <summary>
/// the join table between Post and Category
/// </summary>
public class PostCategoryJoinTable
{
    public int PostId { get; set; }
    public virtual Post Post { get; set; }
    public int CategoryId { get; set; }
    public virtual Category Category { get; set; }
}

After model defined, the relationship must to be configured by using Fluent API. PS: the virtual can NOT be necessary, in the case, using virtual ICollection to enable lazyload.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
	modelBuilder.Entity<PostCategoryJoinTable>()
		.HasKey(x => new { x.PostId , x.CategoryId });

	modelBuilder.Entity<PostCategoryJoinTable>()
		.HasOne(x => x.Post)
		.WithMany(p => p.PostCategories)
		.HasForeignKey(x => x.PostId);

	modelBuilder.Entity<PostCategoryJoinTable>()
		.HasOne(x => x.Category)
		.WithMany(c => c.PostCategories)
		.HasForeignKey(x => x.CategoryId);
}

The primary key of the join table is a composite key including both of the foreign key values. Plus, both sides of the many-to-many relationship are configured by using the HasOne, WithMany and HasForeignKey Fluent API methods.

While the setting is all done, we can call

add-migration YOUR_MIGRATION_NAME -verbose

in Package Manager Console. If nothing wrong, call another command

update-database -verbose

to apply changes to database. When work done, our database built.

img "ef many-2-many"

If, the error occurred by add-migration / update-database is not worked connectly, try to install Microsoft.EntityFrameworkCore.Tools via NuGet.

img "Microsoft.EntityFrameworkCore.Tools"

Please note, the EF Team are scheduling on removing the needed entity / class for a join table someday. The information can be tracked at GitHub and here.


ref:

Relationships

Entity Framework Core tools reference - Package Manager Console in Visual Studio

Fluent API

Configuring Many To Many Relationships in Entity Framework Core

Matt