private void StoreChangedObject(NonNativeObjectInfo
                                 aoi1, NonNativeObjectInfo aoi2, int fieldId
                                 , AbstractObjectInfo oldValue, AbstractObjectInfo
                                 newValue, string message, int objectRecursionLevel)
 {
     if (aoi1 != null && aoi2 != null)
     {
         if (aoi1.GetOid() != null && aoi1.GetOid().Equals(aoi2.GetOid()))
         {
             changedObjectMetaRepresentations.Add(aoi2);
             changes.Add(new ChangedObjectInfo(aoi1
                                               .GetClassInfo(), aoi2.GetClassInfo(), fieldId, oldValue, newValue, message, objectRecursionLevel
                                               ));
             // also the max recursion level
             if (objectRecursionLevel > maxObjectRecursionLevel)
             {
                 maxObjectRecursionLevel = objectRecursionLevel;
             }
             nbChanges++;
         }
         else
         {
             newObjects.Add(aoi2.GetObject());
             string fieldName = aoi1.GetClassInfo().GetAttributeInfoFromId(fieldId).GetName();
             // keep track of the position where the reference must be
             // updated - use aoi1 to get position, because aoi2 do not have position defined yet
             long positionToUpdateReference = aoi1.GetAttributeDefinitionPosition(fieldId);
             StoreNewObjectReference(positionToUpdateReference, aoi2, objectRecursionLevel, fieldName
                                     );
         }
     }
     else
     {
         //newObjectMetaRepresentations.add(aoi2);
         NeoDatis.Tool.DLogger.Info("Non native object with null object");
     }
 }
        private bool HasChanged(NonNativeObjectInfo nnoi1, NonNativeObjectInfo nnoi2, int objectRecursionLevel)
        {
            AbstractObjectInfo value1 = null;
            AbstractObjectInfo value2 = null;
            bool hasChanged           = false;
            // If the object is already being checked, return false, this second
            // check will not affect the check
            int n = 0;

            alreadyCheckingObjects.TryGetValue(nnoi2, out n);
            if (n != 0)
            {
                return(false);
            }
            // Put the object in the temporary cache
            alreadyCheckingObjects[nnoi1] = 1;
            alreadyCheckingObjects[nnoi2] = 1;
            // Warning ID Start with 1 and not 0
            for (int id = 1; id <= nnoi1.GetMaxNbattributes(); id++)
            {
                value1 = nnoi1.GetAttributeValueFromId(id);
                // Gets the value by the attribute id to be sure
                // Problem because a new object info may not have the right ids ?
                // Check if
                // the new oiD is ok.
                value2 = nnoi2.GetAttributeValueFromId(id);
                if (value2 == null)
                {
                    // this means the object to have attribute id
                    StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel);
                    hasChanged = true;
                    continue;
                }
                if (value1 == null)
                {
                    //throw new ODBRuntimeException("ObjectInfoComparator.hasChanged:attribute with id "+id+" does not exist on "+nnoi2);
                    // This happens when this object was created with an version of ClassInfo (which has been refactored).
                    // In this case,we simply tell that in place update is not supported so that the object will be rewritten with
                    // new metamodel
                    supportInPlaceUpdate = false;
                    continue;
                }
                // If both are null, no effect
                if (value1.IsNull() && value2.IsNull())
                {
                    continue;
                }
                if (value1.IsNull() || value2.IsNull())
                {
                    supportInPlaceUpdate = false;
                    hasChanged           = true;
                    StoreActionSetAttributetoNull(nnoi1, id, objectRecursionLevel);
                    continue;
                }
                if (!ClassAreCompatible(value1, value2))
                {
                    if (value2 is NativeObjectInfo)
                    {
                        StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel);
                        StoreChangedAttributeAction(new ChangedNativeAttributeAction
                                                        (nnoi1, nnoi2, nnoi1.GetHeader().GetAttributeIdentificationFromId(id), (NativeObjectInfo
                                                                                                                                )value2, objectRecursionLevel, false, nnoi1.GetClassInfo().GetAttributeInfoFromId
                                                            (id).GetName()));
                    }
                    if (value2 is ObjectReference)
                    {
                        NonNativeObjectInfo nnoi = (NonNativeObjectInfo
                                                    )value1;
                        ObjectReference oref = (ObjectReference
                                                )value2;
                        if (!nnoi.GetOid().Equals(oref.GetOid()))
                        {
                            StoreChangedObject(nnoi1, nnoi2, id, objectRecursionLevel);
                            int attributeIdThatHasChanged = id;
                            // this is the exact position where the object reference
                            // definition is stored
                            long attributeDefinitionPosition = nnoi2.GetAttributeDefinitionPosition(attributeIdThatHasChanged
                                                                                                    );
                            StoreChangedAttributeAction(new ChangedObjectReferenceAttributeAction
                                                            (attributeDefinitionPosition, (ObjectReference
                                                                                           )value2, objectRecursionLevel));
                        }
                        else
                        {
                            continue;
                        }
                    }
                    hasChanged = true;
                    continue;
                }
                if (value1.IsAtomicNativeObject())
                {
                    if (!value1.Equals(value2))
                    {
                        // storeChangedObject(nnoi1, nnoi2, id,
                        // objectRecursionLevel);
                        StoreChangedAttributeAction(new ChangedNativeAttributeAction
                                                        (nnoi1, nnoi2, nnoi1.GetHeader().GetAttributeIdentificationFromId(id), (NativeObjectInfo
                                                                                                                                )value2, objectRecursionLevel, false, nnoi1.GetClassInfo().GetAttributeInfoFromId
                                                            (id).GetName()));
                        hasChanged = true;
                        continue;
                    }
                    continue;
                }
                if (value1.IsCollectionObject())
                {
                    CollectionObjectInfo coi1 = (CollectionObjectInfo)value1;
                    CollectionObjectInfo coi2 = (CollectionObjectInfo)value2;
                    bool collectionHasChanged = ManageCollectionChanges(nnoi1, nnoi2, id, coi1, coi2, objectRecursionLevel);
                    hasChanged = hasChanged || collectionHasChanged;
                    continue;
                }
                if (value1.IsArrayObject())
                {
                    ArrayObjectInfo aoi1            = (ArrayObjectInfo)value1;
                    ArrayObjectInfo aoi2            = (ArrayObjectInfo)value2;
                    bool            arrayHasChanged = ManageArrayChanges(nnoi1, nnoi2, id, aoi1, aoi2, objectRecursionLevel
                                                                         );
                    hasChanged = hasChanged || arrayHasChanged;
                    continue;
                }
                if (value1.IsMapObject())
                {
                    MapObjectInfo moi1          = (MapObjectInfo)value1;
                    MapObjectInfo moi2          = (MapObjectInfo)value2;
                    bool          mapHasChanged = ManageMapChanges(nnoi1, nnoi2, id, moi1, moi2, objectRecursionLevel
                                                                   );
                    hasChanged = hasChanged || mapHasChanged;
                    continue;
                }
                if (value1.IsEnumObject())
                {
                    EnumNativeObjectInfo enoi1 = (EnumNativeObjectInfo)value1;
                    EnumNativeObjectInfo enoi2 = (EnumNativeObjectInfo)value2;
                    bool enumHasChanged        = !enoi1.GetEnumClassInfo().GetId().Equals(enoi2.GetEnumClassInfo
                                                                                              ().GetId()) || !enoi1.GetEnumName().Equals(enoi2.GetEnumName());
                    hasChanged = hasChanged || enumHasChanged;
                    continue;
                }
                if (value1.IsNonNativeObject())
                {
                    NonNativeObjectInfo oi1 = (NonNativeObjectInfo)value1;
                    NonNativeObjectInfo oi2 = (NonNativeObjectInfo)value2;
                    // If oids are equal, they are the same objects
                    if (oi1.GetOid() != null && oi1.GetOid().Equals(oi2.GetOid()))
                    {
                        hasChanged = HasChanged(value1, value2, objectRecursionLevel + 1) || hasChanged;
                    }
                    else
                    {
                        // This means that an object reference has changed.
                        hasChanged = true;
                        // keep track of the position where the reference must be
                        // updated
                        long positionToUpdateReference = nnoi1.GetAttributeDefinitionPosition(id);
                        StoreNewObjectReference(positionToUpdateReference, oi2, objectRecursionLevel, nnoi1
                                                .GetClassInfo().GetAttributeInfoFromId(id).GetName());
                        objectRecursionLevel++;
                        // Value2 may have change too
                        AddPendingVerification(value2);
                    }
                    continue;
                }
            }
            int i1 = (int)alreadyCheckingObjects[nnoi1];
            int i2 = (int)alreadyCheckingObjects[nnoi2];

            if (i1 != null)
            {
                i1 = i1 - 1;
            }
            if (i2 != null)
            {
                i2 = i2 - 1;
            }
            if (i1 == 0)
            {
                alreadyCheckingObjects.Remove(nnoi1);
            }
            else
            {
                alreadyCheckingObjects.Add(nnoi1, i1);
            }
            if (i2 == 0)
            {
                alreadyCheckingObjects.Remove(nnoi2);
            }
            else
            {
                alreadyCheckingObjects.Add(nnoi2, i2);
            }
            return(hasChanged);
        }