Ef Core 5 «many to many» in OnModelCreating with extra fields?

Ef Core 5 предоставляет удобный способ работы с отношениями "многие ко многим" через метод OnModelCreating. Однако, в случае, когда в таком отношении присутствуют дополнительные поля (extra fields), требуется некоторая дополнительная конфигурация.

Для решения этой задачи, необходимо выполнить следующие шаги:

Шаг 1: Создание классов моделей
Создайте классы моделей, которые будут представлять сущности, участвующие в отношении. Для примера, взяты классы EntityA и EntityB, у которых есть отношение "многие ко многим", и присутствует дополнительное поле ExtraField:

public class EntityA
{
    public int Id { get; set; }
    public ICollection<EntityAEntityB> EntityBList { get; set; }
}

public class EntityB
{
    public int Id { get; set; }
    public ICollection<EntityAEntityB> EntityAList { get; set; }
}

public class EntityAEntityB
{
    public EntityA EntityA { get; set; }
    public EntityB EntityB { get; set; }
    public string ExtraField { get; set; }
}

Шаг 2: Определение связей многие ко многим в методе OnModelCreating
В методе OnModelCreating класса DbContext определите связи многие ко многим с помощью метода HasMany(). В данном случае, будет создана промежуточная таблица EntityAEntityBs для связи EntityA и EntityB, а также соответствующие столбцы для ExtraField:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<EntityA>()
        .HasMany(a => a.EntityBList)
        .WithMany(b => b.EntityAList)
        .UsingEntity<EntityAEntityB>(
            j => j.HasOne(eab => eab.EntityB).WithMany(),
            j => j.HasOne(eab => eab.EntityA).WithMany(),
            j =>
            {
                j.HasKey(eab => new { eab.EntityAId, eab.EntityBId });
                j.Property(eab => eab.ExtraField);
            }
        );
}

Шаг 3: Дополнительная конфигурация класса EntityAEntityB
Важным шагом является также дополнительная конфигурация класса EntityAEntityB с помощью метода OnModelCreating. Это позволяет указать свойства первичного ключа и задать ограничения на другие свойства:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // ...

    modelBuilder.Entity<EntityAEntityB>()
        .HasKey(eab => new { eab.EntityAId, eab.EntityBId });

    // ...
}

Это позволит Ef Core 5 правильно связать таблицы и создать необходимые связи "многие ко многим" с дополнительными полями. После этого вы получаете полный контроль над работой с моделями и связями.