/// <summary>
		/// Constructs VersionProperty instances.
		/// </summary>
		/// <param name="name">The name by which the property can be referenced within
		/// its owner.</param>
		/// <param name="node">The node name to use for XML-based representation of this
		/// property.</param>
		/// <param name="type">The Hibernate Type of this property.</param>
		/// <param name="lazy">Should this property be handled lazily?</param>
		/// <param name="insertable">Is this property an insertable value?</param>
		/// <param name="updateable">Is this property an updateable value?</param>
		/// <param name="insertGenerated">Is this property generated in the database on insert?</param>
		/// <param name="updateGenerated">Is this property generated in the database on update?</param>
		/// <param name="nullable">Is this property a nullable value?</param>
		/// <param name="checkable">Is this property a checkable value?</param>
		/// <param name="versionable">Is this property a versionable value?</param>
		/// <param name="cascadeStyle">The cascade style for this property's value.</param>
		/// <param name="unsavedValue">The value which, if found as the value of
		/// this (i.e., the version) property, represents new (i.e., un-saved)
		/// instances of the owning entity.</param>
		public VersionProperty(
			string name,
			string node,
			IType type,
			bool lazy,
			bool insertable,
			bool updateable,
			bool insertGenerated,
			bool updateGenerated,
			bool nullable,
			bool checkable,
			bool versionable,
			Cascades.CascadeStyle cascadeStyle,
			Cascades.VersionValue unsavedValue)
			: base(
				name, node, type, lazy, insertable, updateable, insertGenerated, updateGenerated, nullable, checkable, versionable,
				cascadeStyle)
		{
			this.unsavedValue = unsavedValue;
		}
		protected AbstractEntityPersister( PersistentClass model, ISessionFactoryImplementor factory )
		{
			dialect = factory.Dialect;
			//sqlExceptionConverter = factory.SQLExceptionConverter;

			// CLASS
			className = model.MappedClass.FullName;
			rootClassName = model.RootClazz.Name;
			mappedClass = model.MappedClass;

			mutable = model.IsMutable;
			selectBeforeUpdate = model.SelectBeforeUpdate;
			dynamicUpdate = model.DynamicUpdate;
			dynamicInsert = model.DynamicInsert;
			sqlWhereString = model.Where;
			sqlWhereStringTemplate = sqlWhereString == null ?
				null :
				Template.RenderWhereStringTemplate( sqlWhereString, Dialect );

			polymorphic = model.IsPolymorphic;
			explicitPolymorphism = model.IsExplicitPolymorphism;
			inherited = model.IsInherited;
			superclass = inherited ? model.Superclass.MappedClass : null;
			hasSubclasses = model.HasSubclasses;

			batchSize = model.BatchSize;

			constructor = ReflectHelper.GetDefaultConstructor( mappedClass );
			abstractClass = ReflectHelper.IsAbstractClass( mappedClass );

			entityType = NHibernateUtil.Entity( mappedClass );

			optimisticLockMode = model.OptimisticLockMode;
			if( optimisticLockMode > OptimisticLockMode.Version && !dynamicUpdate )
			{
				throw new MappingException( string.Format( "optimistic-lock setting requires dynamic-update=\'true\': {0}", className ) );
			}

			// verify that the class has a default constructor if it is not abstract - it is considered
			// a mapping exception if the default ctor is missing.
			if( abstractClass == false && constructor == null )
			{
				throw new MappingException( "The mapped class " + mappedClass.FullName + " must declare a default (no-arg) constructor." );
			}

			// IDENTIFIER
			hasEmbeddedIdentifier = model.HasEmbeddedIdentifier;
			IValue idValue = model.Identifier;
			identifierType = idValue.Type;

			if( model.HasIdentifierProperty )
			{
				Mapping.Property idProperty = model.IdentifierProperty;
				identifierPropertyName = idProperty.Name;
				identifierSetter = idProperty.GetSetter( mappedClass );
				identifierGetter = idProperty.GetGetter( mappedClass );
			}
			else
			{
				identifierPropertyName = null;
				identifierGetter = null;
				identifierSetter = null;
			}

			System.Type prox = model.ProxyInterface;
			MethodInfo proxySetIdentifierMethod = null;
			MethodInfo proxyGetIdentifierMethod = null;

			if( model.HasIdentifierProperty && prox != null )
			{
				Mapping.Property idProperty = model.IdentifierProperty;

				PropertyInfo getIdPropertyInfo = idProperty.GetGetter( prox ).Property;

				if( getIdPropertyInfo != null )
				{
					proxyGetIdentifierMethod = getIdPropertyInfo.GetGetMethod( true );
				}

				PropertyInfo setIdPropertyInfo = idProperty.GetSetter( prox ).Property;

				if( setIdPropertyInfo != null )
				{
					proxySetIdentifierMethod = setIdPropertyInfo.GetSetMethod( true );
				}
			}

			// HYDRATE SPAN
			hydrateSpan = model.PropertyClosureCollection.Count;

			// IDENTIFIER 
			int idColumnSpan = model.Identifier.ColumnSpan;
			identifierColumnNames = new string[idColumnSpan];
			identifierAliases = new string[idColumnSpan];

			int i = 0;
			foreach( Column col in idValue.ColumnCollection )
			{
				identifierColumnNames[ i ] = col.GetQuotedName( Dialect );
				identifierAliases[ i ] = col.Alias( Dialect );
				i++;
			}

			// GENERATOR
			identifierGenerator = model.Identifier.CreateIdentifierGenerator( Dialect );
			useIdentityColumn = identifierGenerator is IdentityGenerator;
			identitySelectString = useIdentityColumn ? dialect.IdentitySelectString : null;

			// UNSAVED-VALUE:
			unsavedIdentifierValue = UnsavedValueFactory.GetUnsavedIdentifierValue(
				model.Identifier.NullValue,
				identifierGetter,
				identifierType,
				constructor );

			// VERSION:

			if( model.IsVersioned )
			{
				foreach( Column col in model.Version.ColumnCollection )
				{
					versionColumnName = col.GetQuotedName( Dialect );
					break; //only happens once
				}
			}
			else
			{
				versionColumnName = null;
			}

			if( model.IsVersioned )
			{
				//versionPropertyName = model.Version.Name;
				versioned = true;
				versionGetter = model.Version.GetGetter( mappedClass );
				versionType = ( IVersionType ) model.Version.Type;
			}
			else
			{
				//versionPropertyName = null;
				versioned = false;
				versionGetter = null;
				versionType = null;
			}

			// VERSION UNSAVED-VALUE:
			unsavedVersionValue = model.IsVersioned ?
				UnsavedValueFactory.GetUnsavedVersionValue(
					model.Version.NullValue,
					versionGetter,
					versionType,
					constructor ) :
				Cascades.VersionValue.VersionUndefined;

			// PROPERTIES 

			propertyTypes = new IType[hydrateSpan];
			propertyNames = new string[hydrateSpan];
			propertyUpdateability = new bool[hydrateSpan];
			propertyInsertability = new bool[hydrateSpan];
			propertyNullability = new bool[hydrateSpan];
			getters = new IGetter[hydrateSpan];
			setters = new ISetter[hydrateSpan];
			cascadeStyles = new Cascades.CascadeStyle[hydrateSpan];
			string[ ] setterNames = new string[hydrateSpan];
			string[ ] getterNames = new string[hydrateSpan];
			System.Type[ ] types = new System.Type[hydrateSpan];

			i = 0;
			int tempVersionProperty = -66;
			bool foundCascade = false;
			
			bool foundCustomAccessor = false;

			foreach( Mapping.Property prop in model.PropertyClosureCollection )
			{
				if( prop == model.Version )
				{
					tempVersionProperty = i;
				}
				propertyNames[ i ] = prop.Name;
				if( !prop.IsBasicPropertyAccessor )
				{
					foundCustomAccessor = true;
				}

				getters[ i ] = prop.GetGetter( mappedClass );
				setters[ i ] = prop.GetSetter( mappedClass );
				getterNames[ i ] = getters[ i ].PropertyName;
				setterNames[ i ] = setters[ i ].PropertyName;
				types[ i ] = getters[ i ].ReturnType;
				propertyTypes[ i ] = prop.Type;
				propertyUpdateability[ i ] = prop.IsUpdateable;
				propertyInsertability[ i ] = prop.IsInsertable;
				propertyNullability[ i ] = prop.IsNullable;

				gettersByPropertyName[ propertyNames[ i ] ] = getters[ i ];
				settersByPropertyName[ propertyNames[ i ] ] = setters[ i ];
				typesByPropertyName[ propertyNames[ i ] ] = propertyTypes[ i ];

				cascadeStyles[ i ] = prop.CascadeStyle;
				if( cascadeStyles[ i ] != Cascades.CascadeStyle.StyleNone )
				{
					foundCascade = true;
				}

				i++;
			}

			// NH: reflection optimizer works with custom accessors
			if( /*!foundCustomAccessor &&*/ Cfg.Environment.UseReflectionOptimizer )
			{
				getset = GetSetHelperFactory.Create( MappedClass, Setters, Getters );
			}

			hasCascades = foundCascade;
			versionProperty = tempVersionProperty;

			// CALLBACK INTERFACES
			implementsLifecycle = typeof( ILifecycle ).IsAssignableFrom( mappedClass );
			implementsValidatable = typeof( IValidatable ).IsAssignableFrom( mappedClass );

			cache = model.Cache;

			hasCollections = InitHasCollections();

			// PROXIES
			concreteProxyClass = model.ProxyInterface;
			hasProxy = concreteProxyClass != null;

			if( hasProxy )
			{
				HashedSet proxyInterfaces = new HashedSet();
				proxyInterfaces.Add( typeof( INHibernateProxy ) );

				if( !mappedClass.Equals( concreteProxyClass ) )
				{
					if( !concreteProxyClass.IsInterface )
					{
						throw new MappingException(
							"proxy must be either an interface, or the class itself: " +
								mappedClass.FullName );
					}

					proxyInterfaces.Add( concreteProxyClass );
				}

				if( mappedClass.IsInterface )
				{
					proxyInterfaces.Add( mappedClass );
				}

				if( hasProxy )
				{
					foreach( Subclass subclass in model.SubclassCollection )
					{
						System.Type subclassProxy = subclass.ProxyInterface;
						if( subclassProxy == null )
						{
							throw new MappingException( "All subclasses must also have proxies: "
								+ mappedClass.Name );
						}

						if( !subclass.MappedClass.Equals( subclassProxy ) )
						{
							proxyInterfaces.Add( subclassProxy );
						}
					}
				}

				if( hasProxy )
				{
					proxyFactory = CreateProxyFactory();
					proxyFactory.PostInstantiate( mappedClass, proxyInterfaces, proxyGetIdentifierMethod, proxySetIdentifierMethod );
				}
				else
				{
					proxyFactory = null;
				}
			}
			else
			{
				proxyFactory = null;
			}
		}