【问题标题】:Entity Framework Update Existing Object实体框架更新现有对象
【发布时间】:2012-06-29 19:29:28
【问题描述】:

我在我的数据库中添加了一行,然后返回一个不同的上下文来更新它。我有这门课:

public abstract partial class DataManager<I, C> 
    where C : class, IDomainObject, I, new( ) where I : IDomainObject

C 可能是一个 EntityObject,但这个类不知道。

我的存档如下所示:

    public virtual bool Save( I _item )
    {
        bool rc = true;
        try
        {
        var set = m_Context.GetObjectSet<I, C>( );
        ObjectStateEntry stateEntry = null;
        if( ! m_Context.ObjectStateManager.TryGetObjectStateEntry( ( C ) _item, out stateEntry ) )
        {
            if( _item is EntityObject )
            {
                    if ( _item.IsNew )
                    {
                        set.AddObject( ( C ) _item );
                    }
                    else
                    {
                        try
                        {
                            set.Attach( ( C ) _item );
                        }
                        catch( Exception ex )
                        {
                            set.ApplyCurrentValues( ( C ) _item );
                        }

等等……

在我的测试用例中,TryGetObjectStateEntry 找不到 stateEntry。然而,它是一个 EntityObject,并且它不是新的(IsNew 是我的标志),所以它会到达 else。这是我的问题:set.Attach 抛出此错误

“ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。”

在下一刻,ApplyCurrentValues 抛出这个:

“在 ObjectStateManager 中找不到键与所提供对象的键匹配的对象。验证所提供对象的键值是否与必须应用更改的对象的键值匹配。”

这两者怎么可能是真的?

更多信息:

_item 是由 Get 在另一个上下文中创建的。然后处理了该上下文。那时,_item 有一个 EntityState.Unchanged。我对其进行了一些更改,并将其更改为 EntityState.Modified。 (我没想到,因为上下文(及其 ObjectStateManager)应该已经消失了。)无论如何,一旦它到达 Save(上面),它的状态(由调试器报告)被修改,但我有到那时一个新的背景。如果此时我得到所有 ObjectStateEntries(已添加、已删除、已修改、未更改)的列表,则只有两个,并且 _item 不是其中之一,正如 ApplyCurrentValues 报告的那样,但它无法附加,因为“它是也在那儿!”。也许问题在于它仍然附加到旧的 ObjectStateManager(是否有一些不会让 ObjectStateManager 处理的引用?)。

【问题讨论】:

  • 你调用 context.SaveChanges() 两次了吗?
  • @DannyVarod - 我正在使用 UnitOfWork,我只在处置单元时调用 SaveChanges,同时处置上下文。这是一个 Web 应用程序,因此它的 Context 生命周期非常短。 WcfService 已经用完 UnitOfWork 来获取 _item(我提到的“在另一个上下文中获取”)。但是一旦我们到达 Save,SaveChanges 就没有机会被调用两次了。
  • 您确定您没有从依赖注入框架中两次获得相同的 Uow 吗?
  • @DannyVarod - 我很确定。每次实例化 Uow 以及每次调用 Save 时,我都会写出 Context HashCode。我从试图保存它的上下文中加载行的上下文有一个不同的数字......但是,假设我遗漏了一些东西 - 也许你正在做某事:如何使用相同的 Uow 或调用 SaveChanges 两次导致ApplyCurrentValues 和 Attach 不同意对象是否在 ObjectStateManager 中?请记住,这两个“不同”错误是背靠背的,没有(我的)干预代码。
  • 我没有看到你的 Uow 代码,但是,使用 EF,你可以在调用 AcceptChanges() 之前调用 SaveChanges() 几次。您的其他已保存实体之一是否持有对双重保存对象的引用?

标签: entity-framework entity-framework-4 navigation-properties objectstatemanager


【解决方案1】:

问题是每次初始化 db-context 时,它都会从数据库中获取行,并为每一行分配一个实体键。这意味着由 2 个 db-context 检索的同一行将具有 2 个不同的实体键。实体键就像实体框架中的 id,它被用来代替相关实体的 ID。但是虽然保留了表的约束(没有重复的主键) 希望这是有道理的。

【讨论】:

  • 答案是有道理的,但问题是,同一上下文中的同一个对象如何被Attach报告为“已经存在”而被ApplyCurrentValues报告为“找不到”?
  • 我真的不知道是什么导致了第二个问题。但尝试解决第一个问题,它可能与第二个有关。我建议(快速测试)您使用静态 dbcontext
【解决方案2】:

问题在于您将两个不同的用户附加到同一个组织,但是,组织对象在每种情况下都是不同的实例。

如果组织已经在数据库中,请尝试:

  1. 要么将组织的导航属性设置为 null,要么只设置 OrganizationId 属性。

  2. 或者从数据库中加载组织实体,放到导航道具中。

如果组织不在数据库中:

使用相同的实例(扔掉一个并用另一个替换它)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 2018-05-19
    相关资源
    最近更新 更多