private void MergeScalarProperties( CleanupTuple tuple, List <Tuple <object, NavigationPropertyMetadata> > fixups, MergeStrategy mergeStrategy, bool forceFixup = false) { // geänderte Objekte nur bei ForceUpdate aktualisieren if (mergeStrategy == MergeStrategy.ForceUpdate || _trackingInfoProvider.GetState(tuple.Target) == TrackingState.Unchanged) { ////using (new ChangeTrackingScope(ChangeTracking.Disable, source, target)) ////{ var entity = GetEntityInfo(_model.GetEntityMetadata(tuple.Target)); // Properties kopieren foreach (var prop in entity.ScalarProperties) { var oldValue = prop.GetValue(tuple.Target); var newValue = prop.GetValue(tuple.Source); if (!Equals(oldValue, newValue) || forceFixup) { tuple.TrackProperty(prop); prop.SetValue(tuple.Target, newValue); // ist dieses Skalar Property Schlüssel für ein Navigation Property? NavigationPropertyMetadata navProp; if (entity.ForeignKeyProperties.TryGetValue(prop, out navProp)) { fixups.Add(Tuple.Create(tuple.Target, navProp)); } } } //// weitere Properties kopieren ////var cloneableSource = source as IHasExtendedProperties; ////if (cloneableSource != null) ////{ //// cloneableSource.CopyExtendedProperties(target); ////} if (mergeStrategy == MergeStrategy.ForceUpdate) { switch (_trackingInfoProvider.GetState(tuple.Source).GetValueOrDefault()) { case TrackingState.Unchanged: _trackingInfoProvider.SetState(tuple.Target, TrackingState.Unchanged); break; case TrackingState.Added: _trackingInfoProvider.SetState(tuple.Target, TrackingState.Added); break; case TrackingState.Modified: _trackingInfoProvider.SetState(tuple.Target, TrackingState.Modified); break; case TrackingState.Deleted: _trackingInfoProvider.SetState(tuple.Target, TrackingState.Deleted); break; } } } }
private bool Clean( object source, Dictionary <object, CleanupTuple> cleanedTuples, List <Tuple <object, NavigationPropertyMetadata> > fixups, MergeStrategy mergeStrategy, out CleanupTuple cleanedItem) { // already cleaned; if (cleanedTuples.TryGetValue(source, out cleanedItem)) { return(false); } // Metadaten für Source ermitteln var entity = _model.GetEntityMetadata(source); var entityInfo = GetEntityInfo(entity); object result = null; bool added = false; ////if (source.ChangeTracker.State == ObjectState.Added && !entity.IsPrimaryKeySet(source)) ////{ //// // Neues Objekt ohne Primärschlüssel //// if (!source.ChangeTracker.TemporaryObjectId.HasValue) //// { //// // temporäre Id vergeben //// source.ChangeTracker.TemporaryObjectId = Guid.NewGuid(); //// } //// result = AddTrackedObject(entityInfo, source.ChangeTracker.TemporaryObjectId, source, out added); //// if (!added && result != source) //// { //// // Objekt wurde nicht hinzugefügt und nicht bereits mit der selben temporären Id gefunden //// //throw new InvalidOperationException("object with same temporary id is already tracked!"); //// return result; //// } ////} ////else if (source.ChangeTracker.State == ObjectState.Detached) ////{ //// // Objekt ist detached //// var entityKey = entityInfo.RootType.GetPrimaryKeyObject(source); //// //var key = source.ChangeTracker.TemporaryObjectId ?? entityKey; //// var key = entityKey //// // aus TrackedObjects über temporäre Id oder Primärschlüssel entfernen //// if (key != null //// && (TryRemoveTrackedObject(entityInfo, key) || //// (entityKey != null && TryRemoveTrackedObject(entityInfo, entityKey)))) //// { //// ReplaceItem(entityInfo, source, null); //// } //// result = source; ////} ////else ////{ // Hier muss der Primärschlüssel von source zwingend belegt sein if (!entity.IsPrimaryKeySet(source)) { throw new ArgumentException("primary key must be set if ChangeTracking state is not Added", nameof(source)); } //// temporäre Id durch Primärschlüssel ersetzen ////if (source.ChangeTracker.TemporaryObjectId.HasValue) ////{ //// var tracked = GetTrackedObjectOrDefault(entityInfo, source.ChangeTracker.TemporaryObjectId.Value); //// if (tracked != null) //// { //// if (tracked != source) //// { //// // Primärschlüssel kopieren //// foreach (var prop in entityInfo.ScalarProperties.Where(p => p.IsPrimaryKey)) //// { //// prop.SetValue(tracked, prop.GetValue(source)); //// } //// } //// // Objekt mit temporärer Id aus TrackedObjects entfernen //// //if (entityInfo.RootType.IsPrimaryKeySet(tracked) && tracked.ChangeTracker.TemporaryObjectId.HasValue) //// //{ //// // //TryRemoveTrackedObject(entityInfo, tracked.ChangeTracker.TemporaryObjectId.Value); //// // //tracked.ChangeTracker.TemporaryObjectId = null; //// // //tracked.MarkAsUnchanged(); //// //} //// // Objekt mit Primärschlüssel in TrackedObjects einfügen //// var entityKey = entityInfo.RootType.GetPrimaryKeyObject(tracked); //// result = AddTrackedObject(entityInfo, entityKey, tracked); //// if (result != tracked) //// { //// // in allen getrackten Objekten tracked durch result ersetzen //// ReplaceItem(entityInfo, tracked, result); //// } //// } ////} if (result == null) { // keine temporäre Id oder das Objekt ist mit temporäer Id noch nicht in TrackedObjects // Objekt mit Primärschlüssel in TrackedObjects einfügen var entityKey = entityInfo.RootType.GetPrimaryKeyObject(source); result = AddTrackedObject(entityInfo, entityKey, source, out added); } ////} if (result == null) { // zu diesem Zeitpunkt muss ein Ergbenis feststehen und in TrackedObjects vorhanden sein throw new InvalidOperationException("no result object!"); } CleanupTuple tuple = null; if (source != result) { tuple = new CleanupTuple(source, result, entityInfo); // Objekte nicht Referenzgleich if (_trackingInfoProvider.GetState(source) == TrackingState.Added && _trackingInfoProvider.GetState(result) == TrackingState.Deleted) { MergeScalarProperties(tuple, fixups, MergeStrategy.ForceUpdate, true); } else { MergeScalarProperties(tuple, fixups, mergeStrategy); } // add to cleaned Tuples to avoid endless recoursions. cleanedTuples.Add(source, tuple); } else { tuple = new CleanupTuple(source, result, entityInfo, added); // add to cleaned Tuples to avoid endless recoursions. cleanedTuples.Add(result, tuple); } cleanedItem = tuple; return(true); }