private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntropectAtomicNativeArray
            (object array, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type)
        {
            int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);

            NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo anoi = null;
            object[] arrayCopy = new object[length];
            int      typeId    = 0;

            for (int i = 0; i < length; i++)
            {
                object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
                if (o != null)
                {
                    // If object is not null, try to get the exact type
                    typeId = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.GetFromClass(o.GetType()).GetId
                                 ();
                    anoi         = new NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo(o, typeId);
                    arrayCopy[i] = anoi;
                }
                else
                {
                    // Else take the declared type
                    arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type
                                                                                                 .GetId());
                }
            }
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
                                                                           (arrayCopy, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.Array, type.GetId());
            return(aoi);
        }
        private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntrospectArray(object
                                                                                     array, bool introspect, System.Collections.Generic.IDictionary <object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                                                                                                                                     > alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType valueType, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
                                                                                     callback)
        {
            int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);

            System.Type elementType = array.GetType().GetElementType();
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
                                                                .GetFromClass(elementType);
            if (type.IsAtomicNative())
            {
                return(IntropectAtomicNativeArray(array, type));
            }
            if (!introspect)
            {
                return(new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])array));
            }
            object[] arrayCopy = new object[length];
            for (int i = 0; i < length; i++)
            {
                object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
                NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = null;
                if (o != null)
                {
                    ci = GetClassInfo(OdbClassUtil.GetFullName(o.GetType()));
                    NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = GetObjectInfo(o, ci
                                                                                                , introspect, alreadyReadObjects, callback);
                    arrayCopy[i] = aoi;
                }
                else
                {
                    arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo();
                }
            }
            NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo arrayOfAoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
                                                                                  (arrayCopy, valueType, type.GetId());
            return(arrayOfAoi);
        }
		/// <summary>Checks if something in the Arary has changed, if yes, stores the change</summary>
		/// <param name="nnoi1">
		/// The first Object meta representation (nnoi =
		/// NonNativeObjectInfo)
		/// </param>
		/// <param name="nnoi2">The second object meta representation</param>
		/// <param name="fieldIndex">The field index that this collection represents</param>
		/// <param name="aoi1">The Meta representation of the array 1 (aoi = ArraybjectInfo)</param>
		/// <param name="aoi2">The Meta representation of the array 2</param>
		/// <param name="objectRecursionLevel"></param>
		/// <returns>true if the 2 array representations are different</returns>
		private bool ManageArrayChanges(NonNativeObjectInfo
			 nnoi1, NonNativeObjectInfo nnoi2, int fieldId
			, ArrayObjectInfo aoi1, ArrayObjectInfo
			 aoi2, int objectRecursionLevel)
		{
			object[] array1 = aoi1.GetArray();
			object[] array2 = aoi2.GetArray();
			if (array1.Length != array2.Length)
			{
				System.Text.StringBuilder buffer = new System.Text.StringBuilder();
				buffer.Append("Array size has changed oldsize=").Append(array1.Length).Append("/newsize="
					).Append(array2.Length);
				StoreChangedObject(nnoi1, nnoi2, fieldId, aoi1, aoi2, buffer.ToString(), objectRecursionLevel
					);
				supportInPlaceUpdate = false;
				return true;
			}
			AbstractObjectInfo value1 = null;
			AbstractObjectInfo value2 = null;
			// check if this array supports in place update
			bool localSupportInPlaceUpdate = ODBType.HasFixSize
				(aoi2.GetComponentTypeId());
			int index = 0;
			bool hasChanged = false;
			try
			{
				for (int i = 0; i < array1.Length; i++)
				{
					value1 = (AbstractObjectInfo)array1[i];
					value2 = (AbstractObjectInfo)array2[i];
					bool localHasChanged = this.HasChanged(value1, value2, objectRecursionLevel);
					if (localHasChanged)
					{
						StoreArrayChange(nnoi1, fieldId, i, value2, localSupportInPlaceUpdate);
						if (localSupportInPlaceUpdate)
						{
							hasChanged = true;
						}
						else
						{
							hasChanged = true;
							return hasChanged;
						}
					}
					index++;
				}
			}
			finally
			{
				if (hasChanged && !localSupportInPlaceUpdate)
				{
					supportInPlaceUpdate = false;
				}
			}
			return hasChanged;
		}
 protected virtual NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo GetNativeObjectInfoInternal
     (NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type, object o, bool recursive
     , System.Collections.Generic.IDictionary <object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
                                               > alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
     callback)
 {
     NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = null;
     if (type.IsAtomicNative())
     {
         if (o == null)
         {
             aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type.GetId());
         }
         else
         {
             aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo(o, type
                                                                                   .GetId());
         }
     }
     else
     {
         if (type.IsCollection())
         {
             aoi = IntrospectCollection((System.Collections.ICollection)o, recursive, alreadyReadObjects
                                        , type, callback);
         }
         else
         {
             if (type.IsArray())
             {
                 if (o == null)
                 {
                     aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo(null);
                 }
                 else
                 {
                     // Gets the type of the elements of the array
                     string realArrayClassName = OdbClassUtil.GetFullName(o.GetType().GetElementType());
                     NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo aroi = null;
                     if (recursive)
                     {
                         aroi = IntrospectArray(o, recursive, alreadyReadObjects, type, callback);
                     }
                     else
                     {
                         aroi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])o
                                                                                         );
                     }
                     aroi.SetRealArrayComponentClassName(realArrayClassName);
                     aoi = aroi;
                 }
             }
             else
             {
                 if (type.IsMap())
                 {
                     if (o == null)
                     {
                         aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.MapObjectInfo(null, type, type.GetDefaultInstanciationClass
                                                                                          ().FullName);
                     }
                     else
                     {
                         MapObjectInfo moi = null;
                         string        realMapClassName = OdbClassUtil.GetFullName(o.GetType());
                         bool          isGeneric        = o.GetType().IsGenericType;
                         if (isGeneric)
                         {
                             moi = new MapObjectInfo(IntrospectGenericMap((System.Collections.Generic.IDictionary <object, object>)o, recursive, alreadyReadObjects, callback), type, realMapClassName);
                         }
                         else
                         {
                             moi = new MapObjectInfo(IntrospectNonGenericMap((System.Collections.IDictionary)o, recursive, alreadyReadObjects, callback), type, realMapClassName);
                         }
                         if (realMapClassName.IndexOf("$") != -1)
                         {
                             moi.SetRealMapClassName(OdbClassUtil.GetFullName(type.GetDefaultInstanciationClass()));
                         }
                         aoi = moi;
                     }
                 }
                 else
                 {
                     if (type.IsEnum())
                     {
                         System.Enum enumObject = (System.Enum)o;
                         if (enumObject == null)
                         {
                             aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type.GetSize(
                                                                                                     ));
                         }
                         else
                         {
                             Type   t             = enumObject.GetType();
                             string enumClassName = enumObject == null ? null : OdbClassUtil.GetFullName(enumObject.GetType());
                             // Here we must check if the enum is already in the meta model. Enum must be stored in the meta
                             // model to optimize its storing as we need to keep track of the enum class
                             // for each enum stored. So instead of storing the enum class name, we can store enum class id, a long
                             // instead of the full enum class name string
                             NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = GetClassInfo(enumClassName);
                             string enumValue = enumObject == null ? null : enumObject.ToString();
                             aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.EnumNativeObjectInfo(ci, enumValue
                                                                                                 );
                         }
                     }
                 }
             }
         }
     }
     return(aoi);
 }
		/// <summary>Builds an instance of an array</summary>
		public virtual object BuildArrayInstance(ArrayObjectInfo aoi)
		{
			// first check if array element type is native (int,short, for example)
			ODBType type = ODBType.GetFromName(aoi.GetRealArrayComponentClassName());
			
			System.Type arrayClazz = type.GetNativeClass();
			object array = System.Array.CreateInstance(arrayClazz, aoi.GetArray().Length);
			
			object o = null;
			AbstractObjectInfo aboi = null;
			for (int i = 0; i < aoi.GetArrayLength(); i++)
			{
				aboi = (AbstractObjectInfo)aoi.GetArray()[i];
				if (aboi != null && !aboi.IsDeletedObject() && !aboi.IsNull())
				{
					o = BuildOneInstance(aboi);
					((Array)array).SetValue(o,i);
				}
			}
			return array;
		}
		private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntropectAtomicNativeArray
			(object array, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type)
		{
			int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);
			NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo anoi = null;
			object[] arrayCopy = new object[length];
			int typeId = 0;
			for (int i = 0; i < length; i++)
			{
				object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
				if (o != null)
				{
					// If object is not null, try to get the exact type
					typeId = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.GetFromClass(o.GetType()).GetId
						();
					anoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo(o, typeId);
					arrayCopy[i] = anoi;
				}
				else
				{
					// Else take the declared type
					arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type
						.GetId());
				}
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
				(arrayCopy, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType.Array, type.GetId());
			return aoi;
		}
		protected virtual NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo GetNativeObjectInfoInternal
			(NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type, object o, bool recursive
			, System.Collections.Generic.IDictionary<object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
			> alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
			 callback)
		{
			NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = null;
			if (type.IsAtomicNative())
			{
				if (o == null)
				{
					aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type.GetId());
				}
				else
				{
					aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.AtomicNativeObjectInfo(o, type
						.GetId());
				}
			}
			else
			{
				if (type.IsCollection())
				{
					aoi = IntrospectCollection((System.Collections.ICollection)o, recursive, alreadyReadObjects
						, type, callback);
				}
				else
				{
					if (type.IsArray())
					{
						if (o == null)
						{
							aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo(null);
						}
						else
						{
							// Gets the type of the elements of the array
							string realArrayClassName = OdbClassUtil.GetFullName(o.GetType().GetElementType());
							NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo aroi = null;
							if (recursive)
							{
								aroi = IntrospectArray(o, recursive, alreadyReadObjects, type, callback);
							}
							else
							{
								aroi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])o
									);
							}
							aroi.SetRealArrayComponentClassName(realArrayClassName);
							aoi = aroi;
						}
					}
					else
					{
						if (type.IsMap())
						{
							if (o == null)
							{
								aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.MapObjectInfo(null, type, type.GetDefaultInstanciationClass
									().FullName);
							}
							else
							{
								MapObjectInfo moi = null;
								string realMapClassName = OdbClassUtil.GetFullName(o.GetType());
                                bool isGeneric = o.GetType().IsGenericType;
                                if (isGeneric)
                                {
                                    moi = new MapObjectInfo(IntrospectGenericMap((System.Collections.Generic.IDictionary<object,object>)o, recursive, alreadyReadObjects, callback), type, realMapClassName);
                                }
                                else
                                {
                                    moi = new MapObjectInfo(IntrospectNonGenericMap((System.Collections.IDictionary)o, recursive, alreadyReadObjects, callback), type, realMapClassName);
                                }
								if (realMapClassName.IndexOf("$") != -1)
								{
									moi.SetRealMapClassName(OdbClassUtil.GetFullName(type.GetDefaultInstanciationClass()));
								}
								aoi = moi;
							}
						}
						else
						{
							if (type.IsEnum())
							{
								System.Enum enumObject = (System.Enum)o;
								if (enumObject == null)
								{
									aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NullNativeObjectInfo(type.GetSize(
										));
								}
								else
								{
                                    Type t = enumObject.GetType();
                                    string enumClassName = enumObject == null ? null : OdbClassUtil.GetFullName(enumObject.GetType());
									// Here we must check if the enum is already in the meta model. Enum must be stored in the meta
									// model to optimize its storing as we need to keep track of the enum class
									// for each enum stored. So instead of storing the enum class name, we can store enum class id, a long
									// instead of the full enum class name string
									NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = GetClassInfo(enumClassName);
									string enumValue = enumObject == null ? null : enumObject.ToString();
									aoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.EnumNativeObjectInfo(ci, enumValue
										);
								}
							}
						}
					}
				}
			}
			return aoi;
		}
		private NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo IntrospectArray(object
			 array, bool introspect, System.Collections.Generic.IDictionary<object, NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeObjectInfo
			> alreadyReadObjects, NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType valueType, NeoDatis.Odb.Core.Layers.Layer1.Introspector.IIntrospectionCallback
			 callback)
		{
			int length = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayLength(array);
			System.Type elementType = array.GetType().GetElementType();
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType type = NeoDatis.Odb.Core.Layers.Layer2.Meta.ODBType
				.GetFromClass(elementType);
			if (type.IsAtomicNative())
			{
				return IntropectAtomicNativeArray(array, type);
			}
			if (!introspect)
			{
				return new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo((object[])array);
			}
			object[] arrayCopy = new object[length];
			for (int i = 0; i < length; i++)
			{
				object o = NeoDatis.Tool.Wrappers.OdbReflection.GetArrayElement(array, i);
				NeoDatis.Odb.Core.Layers.Layer2.Meta.ClassInfo ci = null;
				if (o != null)
				{
					ci = GetClassInfo(OdbClassUtil.GetFullName(o.GetType()));
					NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo aoi = GetObjectInfo(o, ci
						, introspect, alreadyReadObjects, callback);
					arrayCopy[i] = aoi;
				}
				else
				{
					arrayCopy[i] = new NeoDatis.Odb.Core.Layers.Layer2.Meta.NonNativeNullObjectInfo();
				}
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo arrayOfAoi = new NeoDatis.Odb.Core.Layers.Layer2.Meta.ArrayObjectInfo
				(arrayCopy, valueType, type.GetId());
			return arrayOfAoi;
		}
		/// <summary>
		/// <pre>
		/// Write an array to the database
		/// This is done by writing :
		/// - the array type : array
		/// - the array element type (String if it os a String [])
		/// - the position of the non native type, if element are non java / C# native
		/// - the number of element s and then the position of all elements.
		/// </summary>
		/// <remarks>
		/// <pre>
		/// Write an array to the database
		/// This is done by writing :
		/// - the array type : array
		/// - the array element type (String if it os a String [])
		/// - the position of the non native type, if element are non java / C# native
		/// - the number of element s and then the position of all elements.
		/// Example : an array with two string element : 'ola' and 'chico'
		/// write 22 : array
		/// write  20 : array of STRING
		/// write 0 : it is a java native object
		/// write 2 (as an int) : the number of elements
		/// write two times 0 (as long) to reserve the space for the elements positions
		/// then write the string 'ola', and keeps its position in the 'positions' array of long
		/// then write the string 'chico' and keeps its position in the 'positions' array of long
		/// Then write back all the positions (in this case , 2 positions) after the size of the array
		/// Example : an array with two User element : user1 and user2
		/// write 22 : array
		/// write  23 : array of NON NATIVE Objects
		/// write 251 : if 250 is the position of the user class info in database
		/// write 2 (as an int) : the number of elements
		/// write two times 0 (as long) to reserve the space for the elements positions
		/// then write the user user1, and keeps its position in the 'positions' array of long
		/// then write the user user2 and keeps its position in the 'positions' array of long
		/// &lt;pre&gt;
		/// &#064;param object
		/// &#064;param odbType
		/// &#064;param position
		/// &#064;param writeInTransaction
		/// &#064;
		/// </remarks>
		private long WriteArray(ArrayObjectInfo aoi, bool writeInTransaction)
		{
			long firstObjectPosition = 0;
			long[] attributeIdentifications;
			long startPosition = fsi.GetPosition();
			WriteNativeObjectHeader(aoi.GetOdbTypeId(), aoi.IsNull(), NeoDatis.Odb.Impl.Core.Layers.Layer3.Block.BlockTypes
				.BlockTypeArrayObject, writeInTransaction);
			if (aoi.IsNull())
			{
				return startPosition;
			}
			object[] array = aoi.GetArray();
			int arraySize = array.Length;
			// Writes the fact that it is an array
			fsi.WriteString(aoi.GetRealArrayComponentClassName(), false, writeInTransaction);
			// write the size of the array
			fsi.WriteInt(arraySize, writeInTransaction, "array size");
			// build a n array to store all element positions
			attributeIdentifications = new long[arraySize];
			// Gets the current position, to know later where to put the
			// references
			firstObjectPosition = fsi.GetPosition();
			// reserve space for object positions : write 'arraySize' long
			// with zero to store each object position
			for (int i = 0; i < arraySize; i++)
			{
				fsi.WriteLong(0, writeInTransaction, "array element pos ", NeoDatis.Odb.Impl.Core.Transaction.DefaultWriteAction
					.DataWriteAction);
			}
			NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo element = null;
			for (int i = 0; i < arraySize; i++)
			{
				element = (NeoDatis.Odb.Core.Layers.Layer2.Meta.AbstractObjectInfo)array[i];
				if (element == null || element.IsNull())
				{
					// TODO Check this
					attributeIdentifications[i] = NeoDatis.Odb.Impl.Core.Layers.Layer3.Engine.StorageEngineConstant
						.NullObjectIdId;
					continue;
				}
				attributeIdentifications[i] = InternalStoreObjectWrapper(element);
			}
			long positionAfterWrite = fsi.GetPosition();
			// now that all objects have been stored, sets their position in the
			// space that have been reserved
			fsi.SetWritePosition(firstObjectPosition, writeInTransaction);
			for (int i = 0; i < arraySize; i++)
			{
				fsi.WriteLong(attributeIdentifications[i], writeInTransaction, "array real element pos"
					, NeoDatis.Odb.Impl.Core.Transaction.DefaultWriteAction.DataWriteAction);
			}
			// Gos back to the end of the array
			fsi.SetWritePosition(positionAfterWrite, writeInTransaction);
			return startPosition;
		}