实体框架不保存修改后的子项

Bob*_*way 24 c# 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; }
}
Run Code Online (Sandbox Code Playgroud)

这是我要调用以保存DevelopmentType的代码 - 它涉及到automapper,因为我们将实体对象与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();
    }
Run Code Online (Sandbox Code Playgroud)

在我的用户界面中,最常见的操作是让用户查看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();
        }
Run Code Online (Sandbox Code Playgroud)

对类型的更改保存,但对ChargeableRate的更改不会.我认为它没有大的帮助,但我想我会添加它.

boi*_*iil 22

问题是,EF不知道更改的DefaultCharges.

通过设置DevelopmentTypeto的状态EntityState.Modified,EF只知道对象DevelopmentType已被更改.但是,这意味着EF只会更新DevelopmentType但不会更新导航属性.

解决方法 - 这不是最佳实践 - 将迭代所有DefaultCharge当前DevelopmentType状态并将实体状态设置为EntityState.Modified.

另外,我建议首先将实体附加到上下文,然后更改状态.

评论后编辑

当您使用DTO时,我想您正在通过不同的层或不同的机器传输这些对象.

在这种情况下,我建议使用自我跟踪实体,因为无法共享一个上下文.这些实体还保持其当前状态(即,新的,更新的,删除的等).关于自我跟踪实体,网上有很多教程.

例如MSDN - 使用自我跟踪实体


JTM*_*Mon 6

据我所知,仅当使用尝试保存父对象的相同上下文检索父对象时,EF 才能保存子实体。即将一个上下文检索的对象附加到另一个上下文,将允许您保存对父对象的更改,但不能保存对子对象的更改。这是旧搜索的结果,基于此我们切换到 NHibernate。如果没记错的话,我能够找到一个链接,EF 团队成员在其中确认了这一点,并且没有计划改变这种行为。不幸的是,此后与该搜索相关的所有链接都已从我的电脑中删除。

由于我不知道您如何检索案例中的对象,因此我不确定这是否与您的案例相关,但将其放在那里以防万一有帮助。

这是将分离对象附加到上下文的链接。

http://www.codeproject.com/Articles/576330/Attaching-detached-POCO-to-EF-DbContext-simple-and


hai*_*770 5

Context.Entry()已经在内部"附加"实体,以使上下文改变它EntityState.

通过呼唤Attach()你改变EntityState回来Unchanged.尝试注释掉这一行.

  • 我尝试使用EF5,它确实将状态从`modified`更改为`changed`. (2认同)