I have the following code that downloads an object from a 3rd party and I want to persist the inserts/updates to my database. There are 10 tables in the model that were created from SQL Server that were generated from the SOAP object. For simplicity I created the following example to only show a single child table (but in reality there are several layers MyTable -> MyTableChild -> MyTableGrandChild), so we can assume that I have a MyTable EntityType and a MyTableChild EntityType where there is an EntityCollection of MyTableChild objects contained in MyTable.
using (Model.MyEntities context = new Model.MyEntities())
{
var MyObjectsFromSQL = from a in context.MyTable select a;
[AutoMapper][1].CreateMap<SOAPChildObject, Model.MyTableChild>();
[AutoMapper][2].Mapper.CreateMap<SOAPObject, Model.MyTable>();
var DownloadedObjects = Mapper.Map<SOAPObject[], IEnumerable<Model.MyTable>>(ArrayOfSOAPObjects);
foreach (var DownloadedObject in DownloadedObjects)
{
Model.MyTable CurrentObject = context.MyTable.Where(a => a.key == D2.key).Single();
// How do I check the changes in the DownloadedObject against
// the MyObjectsFromSQL so I can send the changes back to SQL
}
context.SaveChanges();
}
I have tried a variety of things, however what made sense to me was to try to copy the values from the DownloadedObject into the CurrentObject and let the framework do its magic. That seemed to work for the non-EntityCollection members, but gave me errors for the EntityCollections.
MyObjectsFromSQL.MyStringObject = DownloadedObject.MyStringObject
MyObjectsFromSQL.MyTableChildObject = DownloadedObject.MyTableChildObject; // ERROR: System.InvalidOperationException!
System.InvalidOperationException was unhandled
Message=The EntityCollection has already been initialized. The InitializeRelatedCollection method should only be called to initialize a new EntityCollection during deserialization of an object graph.
Source=System.Data.Entity
StackTrace:
at System.Data.Objects.DataClasses.RelationshipManager.InitializeRelatedCollection[TTargetEntity](String relationshipName, String targetRoleName, EntityCollection`1 entityCollection)
at Model.MyTable.set_MyTableChild(EntityCollection`1 value)
Entity Framework can’t automatically compare collections of related objects, so you’ll need to do this logic yourself.
Rather than setting
MyObjectsFromSQL.MyTableChildObject = DownloadedObject.MyTableChildObject;, you’ll need to compare the collections piece-by-piece, adding items that don’t exist inMyObjectsFromSQL.MyTableChildObjectyet, removing items that don’t appear inDownloadedObject.MyTableChildObject, and updating the scalar values on each item that exists in both.Likewise, if the child objects have other child objects, you’ll need to follow the same pattern, recursively.