Ejemplo n.º 1
0
        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;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        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);
        }