【问题标题】:Merge Self-tracking entities合并自跟踪实体
【发布时间】:2012-05-17 09:10:02
【问题描述】:

数据库中存储的对象图和同一个对象图被序列化成二进制包。包通过网络传输到客户端,然后需要合并包中的数据和数据库中的数据。

合并源码:

        //objList - data from package
        var objectIds = objList.Select(row => row.ObjectId).ToArray();

        //result - data from Database
        var result = SomeService.Instance.LoadObjects(objectIds);

        foreach (var OSobj in objList)
        {
            var obj = result.Objects.ContainsKey(OSobj.ObjectId)
                ? result.Objects[OSobj.ObjectId]
                : result.Objects.CreateNew(OSobj.ObjectId);

            var targetObject = result.DataObjects.Where(x => x.ObjectId == OSobj.ObjectId).FirstOrDefault();

            targetObject.StopTracking();
            var importedProperties = ImportProperties(targetObject.Properties, OSobj.Properties);
            targetObject.Properties.Clear();
            foreach (var property in importedProperties)
            {
                targetObject.Properties.Add(property);
            }
            targetObject.StartTracking();
        }

        return result;

以及 ImportProperties 方法的代码:

static List<Properties> ImportProperties(
        IEnumerable<Properties> targetProperties,
        IEnumerable<Properties> sourceProperties)
    {
        Func<Guid, bool> hasElement = targetProperties
            .ToDictionary(e => e.PropertyId, e => e)
            .ContainsKey;


        var tempTargetProperties = new List<Properties>();
        foreach (var sourceProperty in sourceProperties)
        {
            if (!hasElement(sourceProperty.PropertyId))
            {
                sourceProperty.AcceptChanges();
                tempTargetProperties.Add(sourceProperty.MarkAsAdded());
            }
            else
            {
                sourceProperty.AcceptChanges();
                tempTargetProperties.Add(sourceProperty.MarkAsModified());
            }
        }

        return tempTargetProperties;
    }

服务器像这样保存传入的更改:

_context.ApplyChanges("OSEntities.Objects", entity);
_context.SaveChanges(SaveOptions.DetectChangesBeforeSave);

当服务器尝试保存更改时发生异常:

AcceptChanges 无法继续,因为对象的键值与 ObjectStateManager 中的另一个对象冲突。在调用 AcceptChanges 之前确保键值是唯一的。

但是如果我更改 ImportProperties 方法的代码,则不会出现错误并且更改已成功保存:

static List<Properties> ImportProperties(
        IEnumerable<Properties> targetProperties,
        IEnumerable<Properties> sourceProperties)
    {
        Func<Guid, bool> hasElement = targetProperties.ToDictionary(e => e.PropertyId, e => e).ContainsKey;


        var tempTargetProperties = new List<Properties>();
        foreach (var sourceProperty in sourceProperties)
        {
            if (!hasElement(sourceProperty.PropertyId))
            {
                var newProp = new Properties
                                  {
                                      ElementId = sourceProperty.ElementId,
                                      Name = sourceProperty.Name,
                                      ObjectId = sourceProperty.ObjectId,
                                      PropertyId = sourceProperty.PropertyId,
                                      Value = sourceProperty.Value
                                  };

                tempTargetProperties.Add(newProp);
            }
            else
            {
                var modifiedProp = new Properties
                                       {
                                           ElementId = sourceProperty.ElementId,
                                           Name = sourceProperty.Name,
                                           ObjectId = sourceProperty.ObjectId,
                                           PropertyId = sourceProperty.PropertyId,
                                           Value = sourceProperty.Value
                                       };

                modifiedProp.MarkAsModified();
                tempTargetProperties.Add(modifiedProp);
            }
        }

        return tempTargetProperties;
    }

为什么会有异常?

【问题讨论】:

  • 包传输到客户端的时候合并包和数据库是什么意思?在将新的、更新的或删除的实体传输到服务器时,我只会看到“合并”。 Entity Framework 有两个简单的方法,您已经提到过 context.ApplyChanges() 和 context.SaveChanges()。在这两种方法之上不需要太多恕我直言。
  • 对象图存储在数据库中,同一个对象图被序列化成二进制包。当我们将包传递给客户端时,我们使用的数据可能会发生变化。包和数据库之间的这些更改必须合并。

标签: entity-framework merge self-tracking-entities


【解决方案1】:

当您将对象图(具有 n 级深度导航属性的实体)传输到客户端应用程序时,实体将在其各自的更改跟踪器中记录所做的任何更改。当实体(或对象图)被发送回应用程序的服务器端时,基本上您需要做的就是:

try
{
  using(Entities context = new Entities())
  {
    context.ApplyChanges(someEntity);
    context.SaveChanges();
  }
}
catch
{
  ...
}

我认为不需要您发布上面的所有代码。您想用该代码实现什么目标?

【讨论】:

  • 您不了解问题的本质。对象图序列化为二进制包。包被传送给客户端。客户端从包中获取数据!这就是为什么我不能使用你的代码 - 事实上,这个图不包含在服务器上的存储库中。如果我将此图传输到服务器并使用 ApplyChanges() 方法 - 会发生错误...
  • 如果你这么说......也许你是对的,那么我不能再帮你了,对不起。在我看来,你让事情变得过于复杂了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-04
  • 1970-01-01
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
相关资源
最近更新 更多