0

Graph of objects stored in the database and the same object graph is serialized into a binary package. Package is transmitted over the network to the client, then it is necessary to merge data from the package and data from the database.

Source code of merge:

        //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;

And code of ImportProperties method:

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;
    }

Server save incoming changes like this :

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

When the server tries to save the changes occur exception:

AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

But if I change the code of ImportProperties method, the error does not occur and the changes are saved successfully:

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;
    }

Why is there an exception?

yoozer8
  • 7,361
  • 7
  • 58
  • 93
Gepard_vvk
  • 79
  • 4
  • What do you mean by merging the package and the database when the package is transmitted to the client? I only see a "merge" when transmitting new, updated or deleted entities to the server. Entity Framework has two simple methods that you already mentioned context.ApplyChanges() and context.SaveChanges(). Not very much is needed on top of these two methods imho. – Youp Bernoulli May 21 '12 at 14:59
  • Graph of objects stored in the database and the same object graph is serialized into a binary package. When we pass the package to the client, the data that we used may change. These changes between the package and the database must be merge. – Gepard_vvk May 25 '12 at 10:19

1 Answers1

0

When you transport an object graph (Entity with n-level deep navigation properties) to a client application the entities will record any changes made in their respective change trackers. When entity (or object graph) is sent back to the server side of the application basically all you need to do is:

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

I don't see the need of all the code above you posted. What are you trying to achieve with that code?

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
  • You do not understand the nature of the problem. Object graph serialized to binary package. Package is transmitted to client. Client get data from package! That`s why i cannot use your code - in fact, this graph does not contains in repository on server. If i transfer this graph to server and use ApplyChanges() method - occurs the error... – Gepard_vvk Jun 04 '12 at 06:20
  • If you say so...maybe you're right, I can't help you any further then, sorry. In my opinion you make things overcomplicated. – Youp Bernoulli Jun 05 '12 at 10:23