令人沮丧的这是由数据库优先 Entity Framework 生成的一对相关对象:
public partial class DevelopmentType
{
public DevelopmentType()
{
this.DefaultCharges = new HashSet<DefaultCharge>();
}
public System.Guid RowId { get; set; }
public string Type { get; set; }
public virtual ICollection<DefaultCharge> DefaultCharges { get; set; }
}
public partial class DefaultCharge
{
public System.Guid RowId { get; set; }
public decimal ChargeableRate { get; set; }
public Nullable<System.Guid> DevelopmentType_RowId { get; set; }
public virtual DevelopmentType DevelopmentType { get; set; }
}
这是我用来保存DevelopmentType的代码-它涉及自动映射器,因为我们将实体对象与DTO区分开来:
public void SaveDevelopmentType(DevelopmentType_dto dt)
{
Entities.DevelopmentType mappedDevType = Mapper.Map<DevelopmentType_dto, Entities.DevelopmentType>(dt);
_Context.Entry(mappedDevType).State = System.Data.EntityState.Modified;
_Context.DevelopmentTypes.Attach(mappedDevType);
_Context.SaveChanges();
}
在我的用户界面中,最常见的操作是使用户查看DevelopmentTypes列表并更新其DefaultCharge。因此,当我使用上面的代码进行测试时,它可以正常运行,但实际上没有任何变化。
如果我在调试器中暂停,很明显更改后的DefaultCharge将传递到函数中,并将其附加到要保存的DevelopmentType中。
逐步执行,如果我在Visual Studio中手动更改值,它将保存更新的值。这更令人困惑。
使用SQL Server Profiler监视数据库显示,更新命令仅针对父对象而不针对任何附加对象发出。
我在其他地方有其他类似的代码,可以正常运行。我在这里做错了什么?
编辑:
我发现,如果在调用SaveDevelopmentType之前执行此操作,则:
using (TransactionScope scope = new TransactionScope())
{
dt.Type = "Test1";
dt.DefaultCharges.First().ChargeableRate = 99;
_CILRepository.SaveDevelopmentType(dt);
scope.Complete();
}
保存对类型的更改,但不保存对ChargeableRate的更改。我认为这没有太大帮助,但我想添加一下。
最佳答案
问题是,EF无法识别已更改的DefaultCharges。
通过将DevelopmentType
的状态设置为EntityState.Modified
,EF仅知道对象DevelopmentType
已更改。但是,这意味着EF仅更新DevelopmentType
,而不会更新其导航属性。
一种解决方法-不是最佳实践-将遍历当前DefaultCharge
的所有DevelopmentType
并将实体状态设置为EntityState.Modified
。
另外,我建议先将实体附加到上下文,然后再更改状态。
评论后编辑
在使用DTO时,我想您正在通过不同的层或不同的机器传输这些对象。
在这种情况下,我建议使用自我跟踪实体,因为不可能共享一个上下文。这些实体还保持其当前状态(即,新的,更新的,删除的等)。网上有很多关于自我跟踪实体的教程。
例如MSDN - Working with Self-Tracking Entities
关于c# - Entity Framework 不保存修改后的子代,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18054798/