Я новичок в 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.'
Кто-нибудь может мне помочь или может предложить несколько примеров для изучения? Спасибо.





Сообщение, которое вы читаете, определенно неверное.
Каждое свойство коллекции или навигации по ссылке может Только быть частью отношения Один. В то время как отношение "многие ко многим" с явным объединением реализуется с помощью отношения "один ко многим" два. Сущность соединения содержит свойства навигации ссылки два, но основная сущность имеет только свойство навигации коллекции Один, которое должно быть связано с одним из них, но не с обоими.
Один из способов решения проблемы - добавить второе свойство навигации коллекции:
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 точно соответствует наличию / отсутствию соответствующего свойства навигации.
Обратите внимание, что в обоих случаях вы должны отключить каскад удаления по крайней мере для одного из отношений и вручную удалить связанные объекты соединения перед удалением основного объекта, потому что отношения с саморегулированием всегда создают проблему возможные циклы или несколько каскадных путей, предотвращая использование каскадного удаления.
Привет, мистер Иван, а что, если мне действительно нужны каскады, у меня аналогичный подход, и мне нужен onUpdate: ReferantialAction.Cascade, не могли бы вы просветить меня? :)
@Burak Hehe, конечно. Но ... К сожалению, EF Core не поддерживает обновление (изменение) ключей, поэтому для этого нет быстрой конфигурации. Вы должны вручную изменить сгенерированную миграцию, а затем выполнить обновления с помощью необработанных команд SQL, потому что, как упоминалось в начале, EF Core не позволит вам изменить PK сущности через контекстные API.
Не могли бы вы проверить этот вопрос ... stackoverflow.com/questions/63472076/…
Отличный ответ ...
Огромное спасибо. Я пробовал оба варианта решений, и оба варианта работают отлично. Я потратил много времени на поиски ответа. Мне приходилось задавать вопрос раньше о stackoverflow.