Entity Framework Core 一对一自引用关系失败

Had*_*des 3 entity-relationship entity-framework one-to-one self-referencing-table entity-framework-core

在构建迁移时,我收到以下错误:

无法确定由“Location”类型的导航属性“Location.NorthLocation”表示的关系。手动配置关系,或从模型中忽略此属性。

位置实体:

public class Location
{
    public Guid Id { get; set; }

    public DateTime CreatedWhen { get; set; }
    public string CreatedBy { get; set; }
    public DateTime ModifiedWhen { get; set; }
    public string ModifiedBy { get; set; }

    public Guid? NorthLocationId { get; set; }
    public virtual Location NorthLocation { get; set; }

    public Guid? SouthLocationId { get; set; }
    public virtual Location SouthLocation { get; set; }

    public Guid? EastLocationId { get; set; }
    public virtual Location EastLocation { get; set; }

    public Guid? WestLocationId { get; set; }
    public virtual Location WestLocation { get; set; }

}
Run Code Online (Sandbox Code Playgroud)

类型配置:

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options) : base(options)
    {
    }

    public DbSet<Location> Locations { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<T>().HasKey("Id");
        builder.Entity<T>().Property("Id").ValueGeneratedOnAdd();
        builder.Entity<T>().Property("CreatedWhen").HasDefaultValueSql("GETDATE()").ValueGeneratedOnAdd();
        builder.Entity<T>().Property("ModifiedWhen").IsRequired();
        builder.Entity<T>().Property("CreatedBy").HasMaxLength(50).IsRequired();
        builder.Entity<T>().Property("ModifiedBy").HasMaxLength(50).IsRequired();

        // Locations
        builder.Entity<Location>().HasOne(x => x.NorthLocation).WithOne(x => x.SouthLocation).HasForeignKey(typeof(Location), "NorthLocationId").OnDelete(DeleteBehavior.SetNull);
        builder.Entity<Location>().HasOne(x => x.SouthLocation).WithOne(x => x.NorthLocation).HasForeignKey(typeof(Location), "SouthLocationId").OnDelete(DeleteBehavior.SetNull);
        builder.Entity<Location>().HasOne(x => x.EastLocation).WithOne(x => x.WestLocation).HasForeignKey(typeof(Location), "EastLocationId").OnDelete(DeleteBehavior.SetNull);
        builder.Entity<Location>().HasOne(x => x.WestLocation).WithOne(x => x.EastLocation).HasForeignKey(typeof(Location), "WestLocationId").OnDelete(DeleteBehavior.SetNull);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的目标是拥有一个 Location 实体,它可以自引用它自己的北/南/东/西邻居。

任何人都可以建议为什么我可能会收到此错误?

div*_*ega 5

您的模型配置不正确,因为它将每个导航属性映射了两次。例如SouthLocation,映射为NorthLocationId外键的反向导航和 的直接导航SouthLocationId

每个导航属性(即NorthLocation, SouthLocation, EastLocation, WestLocation)只能映射到一个关系(即一个外键)。

如果我删除关系配置部分的第 2 和第 4 行,模型似乎运行正常。

通常,在 EF Core 中,我们尝试通过让最后一个配置执行 win 来处理冲突配置,但这有一些限制,并且很难预测执行此代码时会发生什么。当然,针对 SQL Server 使用 EF Core 2.0 preview1,我得到了一个不同的异常(SQL Server 的错误,抱怨级联 delte 中的循环依赖),因此我们可能已经改进了我们处理这种情况的方式。

这是代码:


    using System;
    using Microsoft.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore.Metadata;

    namespace ConsoleApp4
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (var db = new MyContext())
                {
                    db.Database.EnsureDeleted();
                    db.Database.EnsureCreated();
                }
            }
        }

        public class MyContext : DbContext
        {
            public DbSet<Location> Locations { get; set; }
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlServer(@"server=(localdb)\mssqllocaldb;database=hey;ConnectRetryCount=0");
            }

            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<Location>().HasKey("Id");
                modelBuilder.Entity<Location>().Property("Id")
                   .ValueGeneratedOnAdd();
                modelBuilder.Entity<Location>().Property("CreatedWhen")
                   .HasDefaultValueSql("GETDATE()")
                   .ValueGeneratedOnAdd();
                modelBuilder.Entity<Location>().Property("ModifiedWhen")
                   .IsRequired();
                modelBuilder.Entity<Location>().Property("CreatedBy")
                   .HasMaxLength(50)
                   .IsRequired();
                modelBuilder.Entity<Location>().Property("ModifiedBy")
                   .HasMaxLength(50)
                   .IsRequired();
                modelBuilder.Entity<Location>()
                   .HasOne(x => x.NorthLocation)
                   .WithOne(x => x.SouthLocation)
                   .HasForeignKey(typeof(Location), "NorthLocationId")
                   .OnDelete(DeleteBehavior.Restrict);
                modelBuilder.Entity<Location>()
                   .HasOne(x => x.EastLocation)
                   .WithOne(x => x.WestLocation)
                   .HasForeignKey(typeof(Location), "EastLocationId")
                   .OnDelete(DeleteBehavior.Restrict);
            }
        }

        public class Location
        {
            public Guid Id { get; set; }
            public DateTime CreatedWhen { get; set; }
            public string CreatedBy { get; set; }
            public DateTime ModifiedWhen { get; set; }
            public string ModifiedBy { get; set; }
            public Guid? NorthLocationId { get; set; }
            public virtual Location NorthLocation { get; set; }
            public Guid? SouthLocationId { get; set; }
            public virtual Location SouthLocation { get; set; }
            public Guid? EastLocationId { get; set; }
            public virtual Location EastLocation { get; set; }
            public Guid? WestLocationId { get; set; }
            public virtual Location WestLocation { get; set; }
        }
    }
Run Code Online (Sandbox Code Playgroud)