使用一对多子项更新派生实体

本文关键字:更新 派生 实体 一对多 | 更新日期: 2023-09-27 18:26:51

我有这些POCO类,它们使用Fluent API和TPT(每类型表)策略进行映射。

public class Base 
{
   ...
}
public class Derived : Base
{
   ...
   public virtual ICollection<Foo> Foos {get; set;} // One-to-Many
}
public class Foo
{
   ...
   public virtual ICollection<Bar> Bars {get; set;} // One-to-Many
}
public class Bar
{
   ...
}

我的存储库是这样的。

public class Repo
{
   public void Update(Base item)
   {
      using (var ctx = new DbContext())
      {
         ctx.Entry(item).State = EntityState.Modified;
         ctx.SaveChanges();
      }
   }
}

行动:

public void DoStuff()
{
   Derived item = repo.GetById(1);
   item.SomeProp = "xyz"; // new value
   item.Foos = GenerateFoosWithBars(); // change children
   repo.Update(item);
}

令我惊讶的是,如果我只更新BaseDerived类,Update实际上是有效的。然而,当我尝试更新"一对多"关系时,情况变得很糟糕。我在EF4中找到了一个关于如何更新一对多实体的教程。我真的希望EF比这更聪明,我的意思是我必须手动完成。。。这与EF的其他一切都不一样。

因此,我开始尝试使用Entry,因为我希望它是通用的(能够使用Entry.OriginalValues更新任何Base派生类),以避免自己编写查询。但现在真的很让球迷失望!Entry.OriginalValues失败,并显示一个异常,说明DbSet<Derived>不存在。这是完全正确的,事实并非如此。但不应该这样做,因为Derived是通过继承映射到DbSet<Base>的。

很明显,我一定做错了什么,或者做了与其他人截然不同的事情,因为我在这件事上找不到任何有用的东西。EF5在这方面没有改进吗?关于我如何处理这个问题,有什么建议吗?

使用一对多子项更新派生实体

首先,我认为在存储库中不需要Update方法,因为EF跟踪更改并在上下文上调用SaveChanges()时应用。其次,问题可能是,当你做:item时,你正在为Foos poperty分配一个新的集合。Foos=生成FoosWithBars();您不应该这样做,因为当EF具体化Derived类型的对象时,它实际上会返回一个代理,该代理覆盖虚拟Foos集合,以使用它跟踪的特殊类型的延迟加载集合。如果您分配了一个不绑定到上下文的自己的不同集合。(我认为英孚不会处理得很好)。您应该做的是修改集合项,而不是集合本身!希望它能有所帮助!