Отношения многие-ко-многим, ссылающиеся на себя

Я новичок в EF. И я столкнулся с проблемой создания отношения «многие ко многим», ссылающегося на себя. Я пробовал использовать решение от: Entity Framework Core: связь "многие ко многим" с одной и той же сущностью

мои сущности:

public class WordEntity
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Json { get; set; }

    public virtual List<WordSinonymEntity> Sinonyms { get; set; }
}


public class WordSinonymEntity
{
    public long WordId { get; set; }
    public virtual WordEntity Word { get; set; }

    public long SinonymId { get; set; }
    public virtual WordEntity Sinonym { get; set; }
}

и следующая конфигурация:

 modelBuilder.Entity<WordSinonymEntity>()
     .HasOne(pt => pt.Sinonym)
     .WithMany(p => p.Sinonyms)
     .HasForeignKey(pt => pt.SinonymId);

modelBuilder.Entity<WordSinonymEntity>()
    .HasOne(pt => pt.Word)
    .WithMany(t => t.Sinonyms)
    .HasForeignKey(pt => pt.WordId);`

но это приводит к следующему исключению.

System.InvalidOperationException: 'Cannot create a relationship between 'WordEntity.Sinonyms' and 'WordSinonymEntity.Word', because there already is a relationship between 'WordEntity.Sinonyms' and 'WordSinonymEntity.Sinonym'. Navigation properties can only participate in a single relationship.'

Кто-нибудь может мне помочь или может предложить несколько примеров для изучения? Спасибо.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
0
5 336
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сообщение, которое вы читаете, определенно неверное.

Каждое свойство коллекции или навигации по ссылке может Только быть частью отношения Один. В то время как отношение "многие ко многим" с явным объединением реализуется с помощью отношения "один ко многим" два. Сущность соединения содержит свойства навигации ссылки два, но основная сущность имеет только свойство навигации коллекции Один, которое должно быть связано с одним из них, но не с обоими.

Один из способов решения проблемы - добавить второе свойство навигации коллекции:

public class WordEntity
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Json { get; set; }

    public virtual List<WordSinonymEntity> Sinonyms { get; set; }
    public virtual List<WordSinonymEntity> SinonymOf { get; set; } // <--
}

и укажите ассоциации через свободный API:

modelBuilder.Entity<WordSinonymEntity>()
     .HasOne(pt => pt.Sinonym)
     .WithMany(p => p.SinonymOf) // <--
     .HasForeignKey(pt => pt.SinonymId)
     .OnDelete(DeleteBehavior.Restrict); // see the note at the end

modelBuilder.Entity<WordSinonymEntity>()
    .HasOne(pt => pt.Word)
    .WithMany(t => t.Sinonyms)
    .HasForeignKey(pt => pt.WordId); 

Другой способ - оставить модель как есть, но сопоставить WordSinonymEntity.Sinonym с ассоциацией однонаправленный (со свойством навигации по ссылкам и без соответствующего свойства навигации по коллекции):

modelBuilder.Entity<WordSinonymEntity>()
     .HasOne(pt => pt.Sinonym)
     .WithMany() // <--
     .HasForeignKey(pt => pt.SinonymId)
     .OnDelete(DeleteBehavior.Restrict); // see the note at the end

modelBuilder.Entity<WordSinonymEntity>()
    .HasOne(pt => pt.Word)
    .WithMany(t => t.Sinonyms)
    .HasForeignKey(pt => pt.WordId); 

Просто убедитесь, что WithMany точно соответствует наличию / отсутствию соответствующего свойства навигации.

Обратите внимание, что в обоих случаях вы должны отключить каскад удаления по крайней мере для одного из отношений и вручную удалить связанные объекты соединения перед удалением основного объекта, потому что отношения с саморегулированием всегда создают проблему возможные циклы или несколько каскадных путей, предотвращая использование каскадного удаления.

Огромное спасибо. Я пробовал оба варианта решений, и оба варианта работают отлично. Я потратил много времени на поиски ответа. Мне приходилось задавать вопрос раньше о stackoverflow.

butek 11.03.2018 12:51

Привет, мистер Иван, а что, если мне действительно нужны каскады, у меня аналогичный подход, и мне нужен onUpdate: ReferantialAction.Cascade, не могли бы вы просветить меня? :)

Burak 18.08.2020 16:50

@Burak Hehe, конечно. Но ... К сожалению, EF Core не поддерживает обновление (изменение) ключей, поэтому для этого нет быстрой конфигурации. Вы должны вручную изменить сгенерированную миграцию, а затем выполнить обновления с помощью необработанных команд SQL, потому что, как упоминалось в начале, EF Core не позволит вам изменить PK сущности через контекстные API.

Ivan Stoev 18.08.2020 17:08

Не могли бы вы проверить этот вопрос ... stackoverflow.com/questions/63472076/…

Burak 18.08.2020 17:43

Отличный ответ ...

LukaszTaraszka 09.04.2021 08:25

Другие вопросы по теме