Entity Framework Core 5 — ошибка с рекурсивной структурой

Я пытаюсь настроить класс структуры сущности, который имеет 4 поля, которые ссылаются на другие поля того же типа или имеют значение null. Мой класс выглядит так:

public class Patch : EntityBase
{
    [Key]
    public int PatchId { get; set; }

    [ForeignKey("NorthPatchId")]
    public virtual Patch NorthPatch { get; set; }

    [ForeignKey("SouthPatchId")]
    public virtual Patch SouthPatch { get; set; }

    [ForeignKey("EastPatchId")]
    public virtual Patch EastPatch { get; set; }

    [ForeignKey("WestPatchId")]
    public virtual Patch WestPatch { get; set; }
}

Это прекрасно работает, если у меня есть только NorthPatch и SouthPatch, но как только я добавляю третий, EastPatch, я получаю следующую ошибку при попытке выполнить миграцию:

System.InvalidOperationException: Unable to determine the relationship represented by navigation 'Patch.NorthPatch' of type 'Patch'.


person Nathan    schedule 23.01.2021    source источник


Ответы (2)


Это довольно крутая ошибка! Я смог продублировать, И в качестве бонуса обнаружил ошибку, о которой сообщалось и которая все еще открыта для EF Core.

Открытая ошибка: https://github.com/dotnet/efcore/issues/21968

Аналогичная проблема: Entity Framework Core One - Ошибка одной самореферентной связи

Временное решение. Удалите атрибуты [ForeignKey] и вместо этого используйте следующее в OnModelConfiguring для своего контекста.

builder.Entity<Patch>()
    .HasOne(x => x.NorthPatch)
    .WithOne()
    .HasForeignKey(typeof(Patch), "NorthPatchId");

builder.Entity<Patch>()
    .HasOne(x => x.SouthPatch)
    .WithOne()
    .HasForeignKey(typeof(Patch), "SouthPatchId");

builder.Entity<Patch>()
    .HasOne(x => x.EastPatch)
    .WithOne()
    .HasForeignKey(typeof(Patch), "EastPatchId");

builder.Entity<Patch>()
    .HasOne(x => x.WestPatch)
    .WithOne()
    .HasForeignKey(typeof(Patch), "WestPatchId");
person Lacutah    schedule 23.01.2021

@Lucutah отвечает на вопрос, как я его написал, но я хотел опубликовать это другое решение, которое, как я обнаружил, стоит посмотреть. Это дает аналогичные результаты, но также автоматически поддерживает отношения между записями Восток/Запад и Север/Юг. Хотя это может быть далеко не так эффективно, в зависимости от того, что вы пытаетесь сделать.

public class Patch : EntityBase
{
    public int PatchId { get; set; }
    public virtual Patch NorthPatch { get; set; }
    public virtual Patch SouthPatch { get; set; }
    public virtual Patch EastPatch { get; set; }
    public virtual Patch WestPatch { get; set; }
}

В контексте..

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Patch>().HasKey("PatchId");

        modelBuilder.Entity<Patch>()
           .HasOne(x => x.NorthPatch)
           .WithOne(x => x.SouthPatch)
           .HasForeignKey(typeof(Patch), "NorthPatchId");
        modelBuilder.Entity<Patch>()
           .HasOne(x => x.EastPatch)
           .WithOne(x => x.WestPatch)
           .HasForeignKey(typeof(Patch), "EastPatchId");
    }
person Nathan    schedule 24.01.2021