Сопоставление Ef core many 2 many

#sql-server #entity-framework #.net-5

#sql-сервер #сущность-фреймворк #.net-5

Вопрос:

У меня есть 3-стороннее отношение «многие ко многим», подобное этому:

 table 1 skill
table 2 instructions
table 3 person
 

Теперь мне нужно иметь способ задать для комбинации навыков и person список инструкций. Я думал о том, чтобы иметь 1 таблицу с этим отображением SkillId, InstructionId и PersonID. Я попытался настроить его с помощью hasOne.Со многими.Имеет ForeignKey, но он не работает. Я получаю сообщение об ошибке

Свойство или навигационная ‘Инструкция’ не может быть добавлена к объекту типа ‘PersonSkillInstruction’, поскольку свойство или навигация с тем же именем уже существуют для объекта типа ‘PersonSkillInstruction’

Если я настрою только первичные ключи и позволю .netcore 5.0 сделать это за меня, я получаю еще одну ошибку

Свойство ‘PersonSkillInstruction.Инструкция’ имеет тип ‘InstructionEntity’, который не поддерживается текущим поставщиком базы данных. Либо измените тип CLR свойства, либо игнорируйте свойство, используя атрибут ‘[NotMapped]’ или используя EntityTypeBuilder.Игнорировать ‘в ‘OnModelCreating’

Я знаю, что мог бы сделать что-то вроде создания «многие ко многим» для person и skill и установить идентификатор, а затем использовать его в сочетании с инструкцией, но это выглядит очень подозрительно.

Как я могу заставить этот 3-способ «многие ко многим» работать?

Я использую .netcore 5.0, ef core, code first и sqlserver

Ответ №1:

Я думаю, что правильно было бы сделать то, что ты сказал:

Я знаю, что мог бы сделать что-то вроде создания множества для многих для person и skill и установить идентификатор, а затем использовать его в сочетании с инструкцией

Тем не менее, здесь у вас есть пример, если вы хотите создать таблицу PersonSkillInstruction.

 public class PersonSkillInstruction
{ 
  [ForeignKey("person")]    
  public int PersonId { get; set; }        
  [ForeignKey("skill")]    
  public int SkillId { get; set; }    
  [ForeignKey("instructions")]    
  public int InstructionId { get; set; }    
  public virtual Person Person { get; set; }
  public virtual Skill Skill { get; set; }
  public virtual Instruction Instruction { get; set; }
}
 

Затем вам нужно установить PK в DbContext следующим образом:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ...
  modelBuilder.Entity<PersonSkillInstruction>()
    .HasKey(t => new { t.PersonId, t.SkillId, t.InstructionId });
// ...
 

После добавления новой миграции вы должны ссылаться на два таких действия, чтобы избежать циклов:

 // ...
  onDelete: ReferentialAction.Restrict
// ...
 

Если в этой таблице будут выполняться тяжелые запросы, я предлагаю использовать суррогатный ключ с уникальным индексом, подобный этому:

 modelBuilder.Entity<PersonSkillInstruction>()
  .HasIndex(t => new { t.PersonId, t.SkillId, t.InstructionId })
  .IsUnique(); 
 

Ссылка о суррогатном ключе