EF Core未跟踪子集合变更

4
我有这些模型。
public class WarehouseAllocation
{
   public int Id { get; set; }
   public Warehouse Warehouse { get; set; }
   public IList<Dispatch> Dispatches { get; set; }
   //---- removed other properties for brevity
}

public class Dispatch 
{
   public int Id { get; set; }
   public IList<DispatchDetail> DispatchDetails { get; set; }
   //---- removed other properties for brevity
}

关于数据库,

Dispatch表中有一个外键WarehouseAllocationId,它指向WarehouseAllocation表。

我使用Fluent API将模型映射到数据库,如下所示:

modelBuilder.Entity<WarehouseAllocation>(m =>
{
    m.ToTable("WarehouseAllocation");

    m.Property(wa => wa.Id).HasColumnName("WarehouseAllocationId")
         .ValueGeneratedOnAdd();

    m.HasKey(wa => wa.Id);

    m.HasOne(wa => wa.Warehouse)
        .WithMany()
        .HasForeignKey("WarehouseId");

    m.HasMany(w => w.Dispatches)
        .WithOne();
});

modelBuilder.Entity<Dispatch>(m =>
{
    m.ToTable("Dispatch");

    m.Property(wa => wa.Id).HasColumnName("DispatchId")
         .ValueGeneratedOnAdd();

    m.HasKey(wa => wa.Id);
});

当我调用dbContext.WarehouseAllocations.Include(w => w.Dispatches).ThenInclude(w => w.DispatchDetails).ToList()时,Ef core会检索所有仓库分配及其包含细节的分派。问题在于当我使用这种方法时:
var warehouseAllocation = dbContext.WarehouseAllocations
    .Include(w => w.Dispatches)
    .ThenInclude(d => d.DispatchDetails)
    .SingleOrDefault(w => w.Id == warehouseAllocationId);

warehouseAllocation.Dispatches.Add(new Dispatch
{
   //--including other properties
   DispatchDetails = new List<DispatchDetail> {
       new DispatchDetail
       {
          //--other properties
       }
   }
});

// call another query that includes WarehouseAllocation

dbContext.ChangeTracker.HasChanges() // this is false

dbContext.SaveChanges() // this keeps returning zero

为什么更改没有被检测到?
更新:
在进行更改之后,在调用SaveChanges()之前,为了业务事件,我调用了一个包括仓库分配的LINQ查询。EF Core会覆盖当前实体状态吗?

你尝试过 dbContext.Dispatches.Add(new Dispatch...) 吗? - Fabio
1
@Fabio 不行,因为根据上述模型,我该如何放置 warehouseAllocationId? - ash
dbContext.Dispatches.Add(new Dispatch { WarehouseAllocationId = warehouseAllocationId , ...}) dbContext.Dispatches.Add(新的调度{ WarehouseAllocationId = warehouseAllocationId,...}) - Fabio
EF Core有“约定优于配置”的概念。你的Fluent API几乎完全重新声明了EF Core约定的默认值。让它为你完成这项工作。(唯一的主要区别是,EF Core将复数形式化你的表格,而不需要显式告诉你不这样做) - Adam Vincent
你的第二个查询可能会使用 AsNoTracking() 有一点效果,但如果你正在尝试在同一个上下文中进行 Query->Make Changes->Query->Make Changes->Save 操作,我建议将它们拆分为2个上下文,或者使用 Unit of Work 模式。 - Adam Vincent
显示剩余5条评论
2个回答

0
问题在于,我在调用SaveChanges()之前进行了另一个查询,其中包括仓库分配。
var shipment = _myDbContext.Shipments
                .Include(s => s.WarehouseAllocations)
                .ThenInclude(s => s.Dispatches)
                .ThenInclude(s => s.DispatchDetails)
                .Include(s => s.WarehouseAllocations)
                .SingleOrDefault(s => s.WarehouseAllocations.Select(w => w.Id).Contains(warheouseAllocationId));

我在Shipment上执行一些业务事件逻辑并保存所有更改。(现在我可以用更好的方式做到这一点)

我猜,如果您在保存更改之前进行包含受影响实体类型的查询,Ef会覆盖实体状态。


-1
如果你改变了:
 var warehouseAllocation = dbContext.WarehouseAllocations
 .Include(w => w.Dispatches)
 .SingleOrDefault(w => w.Id == warehouseAllocationId);

到:

 var warehouseAllocation = dbContext.WarehouseAllocations
 .Include(w => w.Dispatches)
 .ThenInclude(d => d.DispatchDetail)
 .SingleOrDefault(w => w.Id == warehouseAllocationId);

你需要告诉 EF 你希望将 DispatchDetail 加入到它的更改跟踪器中。这也会从数据库中提取 w 的所有 DispatchDetail 值。


它应当告知 EF 您希望将 DispatchDetail 加入其更改跟踪器 -- Include 并非作为这个目的。 - Gert Arnold
无法编译,模型为 public IList<DispatchDetail> DispatchDetails { get; set; } - Adam Vincent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接