Пример #1
0
        /// <summary>
        /// Returns related gids with source according to the association
        /// </summary>
        /// <param name="source">source id</param>
        /// <param name="association">desinition of association</param>
        /// <returns>related gids</returns>
        private List <long> ApplyAssocioationOnSource(long source, Association association)
        {
            List <long> relatedGids = new List <long>();

            if (association == null)
            {
                association = new Association();
            }

            lock (SmartContainer.Instance.Lock2PC)
            {
                IdentifiedObject io = smartContainer.GetEntity(smartContainer.Original, source);

                if (!io.HasProperty(association.PropertyId))
                {
                    throw new Exception(string.Format("Entity with GID = 0x{0:x16} does not contain prperty with Id = {1}.", source, association.PropertyId));
                }

                Property propertyRef = null;
                if (Property.GetPropertyType(association.PropertyId) == PropertyType.Reference)
                {
                    propertyRef = io.GetProperty(association.PropertyId);
                    long relatedGidFromProperty = propertyRef.AsReference();

                    if (relatedGidFromProperty != 0)
                    {
                        if (association.Type == 0 || (short)ModelCodeHelper.GetTypeFromModelCode(association.Type) == ModelCodeHelper.ExtractTypeFromGlobalId(relatedGidFromProperty))
                        {
                            relatedGids.Add(relatedGidFromProperty);
                        }
                    }
                }
                else if (Property.GetPropertyType(association.PropertyId) == PropertyType.ReferenceVector)
                {
                    propertyRef = io.GetProperty(association.PropertyId);
                    List <long> relatedGidsFromProperty = propertyRef.AsReferences();

                    if (relatedGidsFromProperty != null)
                    {
                        foreach (long relatedGidFromProperty in relatedGidsFromProperty)
                        {
                            if (association.Type == 0 || (short)ModelCodeHelper.GetTypeFromModelCode(association.Type) == ModelCodeHelper.ExtractTypeFromGlobalId(relatedGidFromProperty))
                            {
                                relatedGids.Add(relatedGidFromProperty);
                            }
                        }
                    }
                }
                else
                {
                    throw new Exception(string.Format("Association propertyId = {0} is not reference or reference vector type.", association.PropertyId));
                }
            }

            return(relatedGids);
        }
Пример #2
0
        /// <summary>
        /// Test which should be called for all settable properties,
        /// in order to verify functionality of IAccess methods.
        /// </summary>
        /// <param name="propertyId">property ID of settable property</param>
        public virtual void SettablePropertiesTest(ModelCode propertyId)
        {
            Assert.IsTrue(entity.HasProperty(propertyId));

            Property initialValue = generator.Generate(propertyId);

            Assert.NotNull(initialValue);

            entity.SetProperty(initialValue);
            Property currentValue = entity.GetProperty(propertyId);

            Assert.AreEqual(initialValue, currentValue);
        }
Пример #3
0
        /// <summary>
        /// Gets resource description for entity requested by globalId.
        /// </summary>
        /// <param name="globalId">Id of the entity</param>
        /// <param name="properties">List of requested properties</param>
        /// <returns>Resource description of the specified entity</returns>
        public ResourceDescription GetValues(long globalId, List <ModelCode> properties)
        {
            CommonTrace.WriteTrace(CommonTrace.TraceVerbose, String.Format("Getting values for GID = 0x{0:x16}.", globalId));

            try
            {
                IdentifiedObject io = GetEntity(globalId);

                ResourceDescription rd = new ResourceDescription(globalId);

                Property property = null;

                // insert specified properties
                foreach (ModelCode propId in properties)
                {
                    property = new Property(propId);
                    io.GetProperty(property);
                    rd.AddProperty(property);
                }

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, String.Format("Getting values for GID = 0x{0:x16} succedded.", globalId));

                return(rd);
            }
            catch (Exception ex)
            {
                string message = string.Format("Failed to get values for entity with GID = 0x{0:x16}. {1}", globalId, ex.Message);
                throw new Exception(message);
            }
        }
Пример #4
0
        /// <summary>
        /// Gets resource description for entity requested by globalId.
        /// </summary>
        /// <param name="globalId">Id of the entity</param>
        /// <param name="properties">List of requested properties</param>
        /// <returns>Resource description of the specified entity</returns>
        public ResourceDescription GetValues(long globalId, List <ModelCode> properties)
        {
            string message = String.Format("Getting values for GID = 0x{0:x16}.", globalId);

            LogHelper.Log(LogTarget.File, LogService.NMSNetworkModel, " INFO - NetworkModel.cs - " + message);

            try
            {
                ResourceDescription rd;

                lock (SmartContainer.Instance.Lock2PC)
                {
                    IdentifiedObject io = smartContainer.GetEntity(smartContainer.Original, globalId);

                    rd = new ResourceDescription(globalId);

                    Property property = null;

                    // insert specified properties
                    foreach (ModelCode propId in properties)
                    {
                        property = new Property(propId);
                        io.GetProperty(property);
                        rd.AddProperty(property);
                    }

                    message = String.Format("Getting values for GID = 0x{0:x16} succedded.", globalId);
                    LogHelper.Log(LogTarget.File, LogService.NMSNetworkModel, " INFO - NetworkModel.cs - " + message);
                }

                return(rd);
            }
            catch (Exception ex)
            {
                message = string.Format("Failed to get values for entity with GID = 0x{0:x16}. {1}", globalId, ex.Message);
                LogHelper.Log(LogTarget.File, LogService.NMSNetworkModel, " ERROR - NetworkModel.cs - " + message);
                throw new Exception(message);
            }
        }
Пример #5
0
        /// <summary>
        /// Brisanje entiteta iz kopije
        /// </summary>
        /// <param name="rd">Resource description</param>
        private void DeleteEntity(ResourceDescription rd)
        {
            if (rd == null)
            {
                CommonTrace.WriteTrace(CommonTrace.TraceInfo, "Delete entity is not done because update operation is empty.");
                return;
            }

            try
            {
                long globalId = rd.Id;

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Deleting entity with GID ({0:x16}).", globalId);

                //Proveravamo da li GlobalId postoji u kopiji, ako ne postoji zavrsavamo
                if (!this.EntityExists(copy, globalId))
                {
                    string message = String.Format("Failed to delete entity because entity with specified GID ({0:x16}) does not exist in network model.", globalId);
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                //Trazimo entitet koji se brise
                IdentifiedObject io = GetEntity(copy, globalId);

                //Proveravamo da li entitet moze da se brise (moze da se brise ako nije referanciran od drugog entiteta)
                if (io.IsReferenced)
                {
                    Dictionary <ModelCode, List <long> > references = new Dictionary <ModelCode, List <long> >();
                    io.GetReferences(references, TypeOfReference.Target);

                    StringBuilder sb = new StringBuilder();

                    foreach (KeyValuePair <ModelCode, List <long> > kvp in references)
                    {
                        foreach (long referenceGlobalId in kvp.Value)
                        {
                            sb.AppendFormat("0x{0:x16}, ", referenceGlobalId);
                        }
                    }

                    string message = String.Format("Failed to delete entity (GID = 0x{0:x16}) because it is referenced by entities with GIDs: {1}.", globalId, sb.ToString());
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                //Pronadjem sve moled kodove property-a za dati entitet
                List <ModelCode> propertyIds = resourcesDescs.GetAllSettablePropertyIdsForEntityId(io.GlobalId);

                //Brisem reference
                Property property = null;
                foreach (ModelCode propertyId in propertyIds)
                {
                    PropertyType propertyType = Property.GetPropertyType(propertyId);

                    //Ako model kod nije referenca, odbacujemo ga i proveravamo drugi
                    if (propertyType != PropertyType.Reference)
                    {
                        continue;
                    }

                    //Ako jeste uzimamo property sa tim model kodom
                    property = io.GetProperty(propertyId);

                    //Dobijamo id target entiteta
                    long targetGlobalId = property.AsReference();

                    if (targetGlobalId != 0)
                    {
                        //Dobijem target entitet i uradim njegov deep copy
                        IdentifiedObject targetEntity     = GetEntity(copy, targetGlobalId);
                        IdentifiedObject copyTargetEntity = targetEntity.DeepCopy();

                        //Dobijem kontejner target elementa uradim ShallowCopy kontejnera
                        DMSType typeTarget = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(targetEntity.GlobalId);
                        ConatinerShallowCopy(typeTarget);

                        //Zamena originalnog entiteta sa kopijom u novom kontejneru
                        copy[typeTarget].Entities[copyTargetEntity.GlobalId] = copyTargetEntity;

                        //Brise se referenca
                        copyTargetEntity.RemoveReference(propertyId, globalId);
                    }
                }

                //Radimo shallow copy kontejnera
                DMSType type = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(globalId);
                ConatinerShallowCopy(type);
                Container container = GetContainer(copy, type);

                //Brisemo entitet iz kopije
                container.RemoveEntity(globalId);

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Deleting entity with GID ({0:x16}) successfully finished.", globalId);
            }
            catch (Exception ex)
            {
                string message = String.Format("Failed to delete entity (GID = 0x{0:x16}) from model. {1}", rd.Id, ex.Message);
                CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                throw new Exception(message);
            }
        }
Пример #6
0
        /// <summary>
        /// Update entiteta u kopiji
        /// </summary>
        /// <param name="rd">Resource description</param>
        private void UpdateEntity(ResourceDescription rd)
        {
            if (rd == null || rd.Properties == null && rd.Properties.Count == 0)
            {
                CommonTrace.WriteTrace(CommonTrace.TraceInfo, "Update entity is not done because update operation is empty.");
                return;
            }

            try
            {
                long globalId = rd.Id;

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Updating entity with GID ({0:x16}).", globalId);

                if (!this.EntityExists(original, globalId))
                {
                    string message = String.Format("Failed to update entity because entity with specified GID ({0:x16}) does not exist in network model.", globalId);
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                //Dobijam tip objekta koji se ubacuje iz njegovog globalnog identifikatora
                DMSType type = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(globalId);

                //Pravim Shallow kopiju kontejnera tako sto napravim novi kontejner i u njega prevezem sve reference iz originala
                //Ideja: Sve sto dodirnem kopiram
                Container containerCopy = ConatinerShallowCopy(type);

                //Dobijam postojeci objekat koji je isti i za kopiju i za original
                IdentifiedObject io = GetEntity(copy, globalId);

                //Vrsi se deep kopi tog objekta
                IdentifiedObject copyIo = io.DeepCopy();
                //Na mesto original objekta u copy kontejneru ubacujem kopiju tog objekta
                copy[type].Entities[io.GlobalId] = copyIo;

                //Prolazimo kroz sve properties i radimo njihov update
                foreach (Property property in rd.Properties)
                {
                    //Prvo proveravamo da li je property referenca
                    if (property.Type == PropertyType.Reference)
                    {
                        long oldTargetGlobalId = copyIo.GetProperty(property.Id).AsReference();

                        if (oldTargetGlobalId != 0)
                        {
                            //Pronadjem objekat sa kojim je objekat povezan
                            IdentifiedObject oldTargetEntity = GetEntity(copy, oldTargetGlobalId);

                            //Pravi se kopija target entiteta
                            IdentifiedObject copyOldTargetEntity = oldTargetEntity.DeepCopy();

                            //Dobijem kontejner target elementa uradim ShallowCopy kontejnera
                            DMSType typeTarget = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(oldTargetEntity.GlobalId);
                            ConatinerShallowCopy(typeTarget);

                            //Zamena originalnog entiteta sa kopijom u novom kontejneru
                            copy[typeTarget].Entities[copyOldTargetEntity.GlobalId] = copyOldTargetEntity;

                            //Ukolonim tu referencu
                            copyOldTargetEntity.RemoveReference(property.Id, globalId);
                        }

                        //Postavim id nove reference
                        long targetGlobalId = property.AsReference();

                        if (targetGlobalId != 0)
                        {
                            if (!EntityExists(copy, targetGlobalId))
                            {
                                string message = string.Format("Failed to get target entity with GID: 0x{0:X16}.", targetGlobalId);
                                throw new Exception(message);
                            }

                            //Pronadjem novi obejak na koji je povezan i setujem mu referencu
                            IdentifiedObject targetEntity = GetEntity(copy, targetGlobalId);

                            //Pravii se kopija target entiteta
                            IdentifiedObject copyTargetEntity = targetEntity.DeepCopy();

                            //Dobijem kontejner target elementa uradim ShallowCopy kontejnera
                            DMSType typeTarget = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(targetEntity.GlobalId);
                            ConatinerShallowCopy(typeTarget);

                            //Zamena originalnog entiteta sa kopijom u novom kontejneru
                            copy[typeTarget].Entities[targetEntity.GlobalId] = copyTargetEntity;

                            copyTargetEntity.AddReference(property.Id, globalId);
                        }

                        //Odradi update ostalih properties
                        copyIo.SetProperty(property);
                    }
                    else
                    {
                        //Odradi update ostalih properties
                        copyIo.SetProperty(property);
                    }
                }

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Updating entity with GID ({0:x16}) successfully finished.", globalId);
            }
            catch (Exception ex)
            {
                string message = String.Format("Failed to update entity (GID = 0x{0:x16}) in model. {1} ", rd.Id, ex.Message);
                CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                throw new Exception(message);
            }
        }
Пример #7
0
        /// <summary>
        /// Deletes resource from the netowrk model.
        /// </summary>
        /// <param name="rd">Description of the resource that should be deleted</param>
        private void DeleteEntity(ResourceDescription rd)
        {
            if (rd == null)
            {
                CommonTrace.WriteTrace(CommonTrace.TraceInfo, "Delete entity is not done because update operation is empty.");
                return;
            }

            try
            {
                long globalId = rd.Id;

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Deleting entity with GID ({0:x16}).", globalId);

                // check if entity exists
                if (!this.EntityExists(globalId))
                {
                    string message = String.Format("Failed to delete entity because entity with specified GID ({0:x16}) does not exist in network model.", globalId);
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                // get entity to be deleted
                IdentifiedObject io = GetEntity(globalId);

                // check if entity could be deleted (if it is not referenced by any other entity)
                if (io.IsReferenced)
                {
                    Dictionary <ModelCode, List <long> > references = new Dictionary <ModelCode, List <long> >();
                    io.GetReferences(references, TypeOfReference.Target);

                    StringBuilder sb = new StringBuilder();

                    foreach (KeyValuePair <ModelCode, List <long> > kvp in references)
                    {
                        foreach (long referenceGlobalId in kvp.Value)
                        {
                            sb.AppendFormat("0x{0:x16}, ", referenceGlobalId);
                        }
                    }

                    string message = String.Format("Failed to delete entity (GID = 0x{0:x16}) because it is referenced by entities with GIDs: {1}.", globalId, sb.ToString());
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                // find property ids
                List <ModelCode> propertyIds = resourcesDescs.GetAllSettablePropertyIdsForEntityId(io.GlobalId);

                // remove references
                Property property = null;
                foreach (ModelCode propertyId in propertyIds)
                {
                    PropertyType propertyType = Property.GetPropertyType(propertyId);

                    if (propertyType == PropertyType.Reference)
                    {
                        property = io.GetProperty(propertyId);

                        if (propertyType == PropertyType.Reference)
                        {
                            // get target entity and remove reference to another entity
                            long targetGlobalId = property.AsReference();

                            if (targetGlobalId != 0)
                            {
                                // get target entity
                                IdentifiedObject targetEntity = GetEntity(targetGlobalId);

                                // remove reference to another entity
                                targetEntity.RemoveReference(propertyId, globalId);
                            }
                        }
                    }
                }

                // remove entity form netowrk model
                DMSType   type      = (DMSType)ModelCodeHelper.ExtractTypeFromGlobalId(globalId);
                Container container = GetContainer(type);
                container.RemoveEntity(globalId);

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Deleting entity with GID ({0:x16}) successfully finished.", globalId);
            }
            catch (Exception ex)
            {
                string message = String.Format("Failed to delete entity (GID = 0x{0:x16}) from model. {1}", rd.Id, ex.Message);
                CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                throw new Exception(message);
            }
        }
Пример #8
0
        /// <summary>
        /// Updates entity in block model.
        /// </summary>
        /// <param name="rd">Description of the resource that should be updated</param>
        private void UpdateEntity(ResourceDescription rd)
        {
            if (rd == null || rd.Properties == null && rd.Properties.Count == 0)
            {
                CommonTrace.WriteTrace(CommonTrace.TraceInfo, "Update entity is not done because update operation is empty.");
                return;
            }

            try
            {
                long globalId = rd.Id;

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Updating entity with GID ({0:x16}).", globalId);

                if (!this.EntityExists(globalId))
                {
                    string message = String.Format("Failed to update entity because entity with specified GID ({0:x16}) does not exist in network model.", globalId);
                    CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                    throw new Exception(message);
                }

                IdentifiedObject io = GetEntity(globalId);

                // updating properties of entity
                foreach (Property property in rd.Properties)
                {
                    if (property.Type == PropertyType.Reference)
                    {
                        long oldTargetGlobalId = io.GetProperty(property.Id).AsReference();

                        if (oldTargetGlobalId != 0)
                        {
                            IdentifiedObject oldTargetEntity = GetEntity(oldTargetGlobalId);
                            oldTargetEntity.RemoveReference(property.Id, globalId);
                        }

                        // updating reference of entity
                        long targetGlobalId = property.AsReference();

                        if (targetGlobalId != 0)
                        {
                            if (!EntityExists(targetGlobalId))
                            {
                                string message = string.Format("Failed to get target entity with GID: 0x{0:X16}.", targetGlobalId);
                                throw new Exception(message);
                            }

                            IdentifiedObject targetEntity = GetEntity(targetGlobalId);
                            targetEntity.AddReference(property.Id, globalId);
                        }

                        // update value of the property in specified entity
                        io.SetProperty(property);
                    }
                    else
                    {
                        // update value of the property in specified entity
                        io.SetProperty(property);
                    }
                }

                CommonTrace.WriteTrace(CommonTrace.TraceVerbose, "Updating entity with GID ({0:x16}) successfully finished.", globalId);
            }
            catch (Exception ex)
            {
                string message = String.Format("Failed to update entity (GID = 0x{0:x16}) in model. {1} ", rd.Id, ex.Message);
                CommonTrace.WriteTrace(CommonTrace.TraceError, message);
                throw new Exception(message);
            }
        }
Пример #9
0
        public override void Update()
        {
            Grid grid = (Grid)((Border)((StackPanel)panel.Children[1]).Children[0]).Child;

            if (grid.Children.Count > 3)
            {
                grid.Children.RemoveRange(3, grid.Children.Count - 3);
            }

            if (grid.RowDefinitions.Count > 1)
            {
                grid.RowDefinitions.RemoveRange(1, grid.RowDefinitions.Count - 1);
            }

            IdentifiedObject io = ioGetter();

            List <ModelCode> props;

            if (io == null || !typeToProps.TryGetValue(ModelCodeHelper.GetTypeFromGID(io.GID), out props))
            {
                Grid.SetColumnSpan(AddToGrid(grid, new TextBlock()
                {
                    Text = "No properties."
                }, 1, 0), int.MaxValue);
                Grid.SetRowSpan(grid.Children[2], 1);
                return;
            }

            List <KeyValuePair <string, UIElement> > rows = new List <KeyValuePair <string, UIElement> >();

            foreach (ModelCode prop in props)
            {
                Property p = io.GetProperty(prop);

                if (p == null)
                {
                    continue;
                }

                UIElement element;

                switch (p.Type)
                {
                case PropertyType.Bool:
                    element = new TextBlock()
                    {
                        Text = ((BoolProperty)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.Enum:
                    element = new TextBlock()
                    {
                        Text = ((EnumProperty)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.Float:
                    element = new TextBlock()
                    {
                        Text = ((FloatProperty)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.Int32:
                    element = new TextBlock()
                    {
                        Text = ((Int32Property)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.Int64:
                    element = new TextBlock()
                    {
                        Text = ((Int64Property)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.Reference:
                {
                    long value = ((ReferenceProperty)p).Value;

                    if (value != 0)
                    {
                        TextBlock tb = CreateHyperlink(value.ToString(), () => new ElementWindow(value, pubSub)
                            {
                                Owner = Application.Current.MainWindow
                            }.Show());
                        tb.TextAlignment = TextAlignment.Right;
                        element          = tb;
                    }
                    else
                    {
                        element = new TextBlock()
                        {
                            Text = value.ToString(), TextAlignment = TextAlignment.Right
                        };
                    }
                }
                break;

                case PropertyType.String:
                    element = new TextBlock()
                    {
                        Text = ((StringProperty)p).Value.ToString(), TextAlignment = TextAlignment.Right
                    };
                    break;

                case PropertyType.ReferenceVector:
                {
                    List <long> values = ((ReferencesProperty)p).Value;
                    StackPanel  sp     = new StackPanel();

                    for (int j = 0; j < values.Count; ++j)
                    {
                        long      value = values[j];
                        TextBlock tb    = CreateHyperlink(value.ToString(), () => new ElementWindow(value, pubSub)
                            {
                                Owner = Application.Current.MainWindow
                            }.Show());
                        tb.TextAlignment = TextAlignment.Right;
                        sp.Children.Add(tb);
                    }

                    element = new ScrollViewer()
                    {
                        MaxHeight = 100, Content = sp, VerticalScrollBarVisibility = ScrollBarVisibility.Auto
                    };
                }
                break;

                default:
                    continue;
                }

                rows.Add(new KeyValuePair <string, UIElement>(prop.ToString(), element));
            }

            rows.Sort((x, y) => { return(x.Key.CompareTo(y.Key)); });

            int i;

            for (i = 0; i < rows.Count; ++i)
            {
                var row = rows[i];
                grid.RowDefinitions.Add(new RowDefinition());
                AddToGrid(grid, new TextBlock()
                {
                    Text = row.Key
                }, i + 1, 0);
                AddToGrid(grid, row.Value, i + 1, 2);
            }

            if (i == 0)
            {
                Grid.SetColumnSpan(AddToGrid(grid, new TextBlock()
                {
                    Text = "No properties."
                }, 1, 0), int.MaxValue);
                Grid.SetRowSpan(grid.Children[2], 1);
            }
            else
            {
                Grid.SetRowSpan(grid.Children[2], int.MaxValue);
            }

            initialized = true;
        }
Пример #10
0
        Tuple <IdentifiedObject, IdentifiedObject> UpdateEntity(ResourceDescription rd)
        {
            if (rd == null)
            {
                return(null);
            }

            IdentifiedObject oldIO;
            Container        container;

            if (!TryGetEntity(rd.Id, out oldIO, out container))
            {
                return(null);
            }

            IdentifiedObject io = oldIO.Clone();

            foreach (Property prop in rd.Properties.Values)
            {
                if (prop.Type == PropertyType.Reference)
                {
                    long oldTargetGID = ((ReferenceProperty)io.GetProperty(prop.Id)).Value;

                    if (oldTargetGID != 0)
                    {
                        IdentifiedObject oldTarget;
                        Container        oldTargetContainer;

                        if (TryGetEntity(oldTargetGID, out oldTarget, out oldTargetContainer))
                        {
                            oldTarget = oldTarget.Clone();
                            oldTarget.RemoveTargetReference(prop.Id, io.GID);
                            oldTargetContainer.Set(oldTarget);
                        }
                    }

                    long targetGID = ((ReferenceProperty)prop).Value;

                    if (targetGID != 0)
                    {
                        IdentifiedObject target;
                        Container        targetContainer;

                        if (TryGetEntity(targetGID, out target, out targetContainer))
                        {
                            target = target.Clone();
                            target.AddTargetReference(prop.Id, io.GID);
                            targetContainer.Set(target);
                        }
                    }
                }

                if (!io.SetProperty(prop))
                {
                    return(null);
                }
            }

            container.Set(io);
            return(new Tuple <IdentifiedObject, IdentifiedObject>(oldIO, io));
        }