多对多的自我引用表 - guid Id自行更改

问题描述 投票:1回答:1

我有很多参考的表。它本身听起来很疯狂所以这里是一个更好地查看问题https://i.stack.imgur.com/lj2zZ.png的图像

我使用guids作为主键和外键。当我尝试将Foo的新实例添加到与数据库中的某些foo有关系的数据库时,以及在传递myDbContext.Set<Foo>().Add(foo);行的确切时刻,Guid https://i.stack.imgur.com/WlFW9.png变为https://i.stack.imgur.com/989nb.png

创建数据库的代码:

 internal class Foo
    {
        public Guid Id { get; set; }
        public string Title { get; set; }

        public virtual List<DependencyFoo> Dependents { get; set; }
        public virtual List<DependencyFoo> DependentsOf { get; set; }
    }

   internal class DependencyFoo
    {
        public virtual Foo Dependent { get; set; }
        public Guid DependentId { get; set; }

        public virtual Foo DependentOf { get; set; }
        public Guid DependentOfId { get; set; }
    }

internal class MyDbContext : DbContext
    {
        public DbSet<Foo> Foos { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Data Source=.\\SQLEXPRESS;Initial Catalog=fooDb;Trusted_Connection=True;Integrated Security=True");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<DependencyFoo>()
              .HasKey(x => new { x.DependentOfId, x.DependentId });

            modelBuilder.Entity<DependencyFoo>()
                .HasOne(x => x.DependentOf)
                .WithMany(x => x.DependentsOf)
                .HasForeignKey(x => x.DependentOfId)
                .OnDelete(DeleteBehavior.Restrict);

            modelBuilder.Entity<DependencyFoo>()
                .HasOne(x => x.Dependent)
                .WithMany(x => x.Dependents)
                .HasForeignKey(x => x.DependentId);
        }
    }

实际测试:

internal class Program
    {
        private static void Main(string[] args)
        {
            MyDbContext myDbContext = new MyDbContext();
            myDbContext.Set<Foo>().Add(new Foo { Title = "Some cool title" });
            myDbContext.SaveChanges();

            Foo fooDb = myDbContext.Set<Foo>().FirstOrDefault(x => x.Title == "Some cool title");
            DependencyFoo dependencyFoo = new DependencyFoo
            {
                DependentOfId = fooDb.Id
            };

            Foo foo = new Foo
            {
                DependentsOf = new List<DependencyFoo>()
            };
            foo.DependentsOf.Add(dependencyFoo);

            myDbContext.Set<Foo>().Add(foo);
        }
    }

知道为什么会这样吗?它是否必须与我做一些事情

关系还是? PS(这个例子用食物简化:))

.net asp.net-core entity-framework-core asp.net-core-2.1 entity-framework-core-2.1
1个回答
1
投票

我相信问题在于映射Foo.Dependents <-> DependencyFoo.DependentFoo.DependentsOf <-> DependencyFoo.DependentOf

foo的实际家属/家属应该真的像(伪代码):

IEnumerable<Foo> fooDependents = db.Set<DependencyFoo>()
    .Where(d => d.DependentOf.Id == foo.Id)
    .Select(d => d.Dependent);

IEnumerable<Foo> fooDependentsOf = db.Set<DependencyFoo>()
    .Where(d => d.Dependent.Id == foo.Id)
    .Select(d => d.DependentOf);

请注意如何交换链接实体中主要实体和引用导航属性中的集合角色。要获得依赖项,您必须选择依赖于依赖的链接依赖项。反之亦然。

目前你设置dependencyFoo.DependentOfId = fooDb.Idfoo.DependentsOf.Add(dependencyFoo);。它们都代表同一个,所以当你调用add时,EF Core fixup会为for.Id生成新的Guid并将其分配给dependencyFoo.DependentOfId。与此同时,dependencyFoo.Dependent仍然是null,因为dependencyFoo.DependentId值是Guid.Empty,EF Core创造并指定一个新的Guid。

要解决此问题,只需在流畅的映射中交换集合:

modelBuilder.Entity<DependencyFoo>()
    .HasOne(x => x.DependentOf)
    .WithMany(x => x.Dependents)
    .HasForeignKey(x => x.DependentOfId)
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<DependencyFoo>()
    .HasOne(x => x.Dependent)
    .WithMany(x => x.DependentsOf)
    .HasForeignKey(x => x.DependentId);

或者(效果相同,我发现它更容易阅读和遵循):

modelBuilder.Entity<Foo>()
    .HasMany(x => x.Dependents)
    .WithOne(x => x.DependentOf)
    .HasForeignKey(x => x.DependentOfId)
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<Foo>()
    .HasMany(x => x.DependentsOf)
    .WithOne(x => x.Dependent)
    .HasForeignKey(x => x.DependentId);
© www.soinside.com 2019 - 2024. All rights reserved.