Как передать через метод POST сущности со связью Many-to-Many?

Проектирую MVC - приложение и возникли затруднения с добавлением данных в БД. Имею базу данных с 3 сущностями, между которыми связь Many-to-Many:

public class Employee
{
[Required] public long Id { get; set; }

[Required] public string Name { get; set; } = null!;

public ICollection<EmployeeSkill>? Skill { get; set; }
}

public class Skill
{
[Required] public long Id { get; set; }
[Required] public string Name { get; set; }

public ICollection<EmployeeSkill>? Employees { get; set; }
}


public class EmployeeSkill
{
[Required] public long EmployeeId { get; set; }
[Required,ForeignKey("EmployeeId")] public Employee Employee{ get; set; }


[Required] public long SkillId { get; set; }
[Required,ForeignKey("SkillId")] public Skill Skill{ get; set; }

[Required] public byte Level { get; set; }
}

Данные сущности необходимо передать в контроллер, в методе POST и создать далее соответствующие строки таблицы. Благодарю за ответы!


Ответы (1 шт):

Автор решения: Alexander Petrov

Для создания этих сущностей вам нужно имя работника, название умения и уровень.
Создадим модель для них:

public class EmployeeSkillModel
{
    public string EmployeeName { get; set; }
    public string SkillName { get; set; }
    public byte Level { get; set; }
}

Метод контроллера должен иметь параметр этого типа. Что-то вроде:

[HttpPost]
public ActionResult Create(EmployeeSkillModel employeeSkillModel)

Далее делаем валидацию (оставляю это вам) и создаём наши сущности:

var employee = new Employee { Name = employeeSkillModel.EmployeeName };
var skill = new Skill { Name = employeeSkillModel.SkillName };
var employeeSkill = new EmployeeSkill { Employee = employee, Skill = skill, Level = employeeSkillModel.Level };

db.EmployeeSkills.Add(employeeSkill);

db.SaveChanges();


Теперь немного выскажу свои мысли.

В ваших моделях Employee и Skill определены свойства-коллекции EmployeeSkill - это так называемые join entity (сущность соединения). Я бы порекомендовал сделать прямые навигационные свойства:

public class Employee
{
    [Required] public long Id { get; set; }
    [Required] public string Name { get; set; } = null!;

    public ICollection<Skill>? Skills { get; set; }
    public ICollection<EmployeeSkill>? EmployeeSkills { get; set; }
}

public class Skill
{
    [Required] public long Id { get; set; }
    [Required] public string Name { get; set; }

    public ICollection<Employee>? Employees { get; set; }
    public ICollection<EmployeeSkill>? EmployeeSkills { get; set; }
}

При этом join entity можно оставить, т. к. она у вас имеет payload (нагрузку) в виде свойства Level и к ней нужно иметь доступ.
Обратите внимание, что имена коллекций во множественном числе.


Вероятно, навыки в БД не должны повторяться. Для этого на свойство Name сущности Skill следует навесить ограничение уникальности: [Index(nameof(Name), IsUnique = true)]. То есть если в БД уже имеется Skill с каким-то названием, то не создавать новый, а использовать имеющийся.

→ Ссылка