实体框架核心一对一自引用关系失败 [英] Entity Framework Core One-One Self Referencing Relationship fails

本文介绍了实体框架核心一对一自引用关系失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

构建迁移时,出现以下错误:

When building the migration I get the following error:

无法确定类型为"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; }

}

类型配置:

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);
    }

}

我的目标是拥有一个Location实体,该实体将自己的邻居自引用为北/南/东/西.

My goal is to have a Location entity that self-references it's own neighbours to the north/south/east/west.

任何人都可以建议我为什么会出现此错误吗?

Can anyone suggest why I might be getting this error?

推荐答案

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

Your model configuration is incorrect because it maps each of the navigation properties twice. E.g. SouthLocation is mapped both as the reverse navigation for the NorthLocationId foreign key and as the direct navigation for SouthLocationId.

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

Each navigation property (i.e. NorthLocation, SouthLocation, EastLocation, WestLocation) can only be mapped to one relationship (i.e. to one foreign key).

如果删除关系配置部分的第二行和第四行,则该模型似乎正常运行.

If I delete the 2nd and 4th lines of the relationship configuration part, the model seems to be functioning properly.

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

In general in EF Core we try to deal with conflicting configuration by letting the last configuration to execute win, but this has some limitations and it is hard to anticipate what can happen when you execute this code. Certainly, using EF Core 2.0 preview1 against SQL Server, I got a different exception (an error form SQL Server, complaining about cyclic dependencies in cascade delte), so it is possible that we have improved how we handle this scenario.

这是代码:


    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; }
        }
    }

这篇关于实体框架核心一对一自引用关系失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆