我有很多参考的表。它本身听起来很疯狂所以这里是一个更好地查看问题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(这个例子用食物简化:))
我相信问题在于映射Foo.Dependents <-> DependencyFoo.Dependent
和Foo.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.Id
和foo.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);