Пример #1
0
        // 6.0 TODO: Move to IProxyFactory
        public static void PostInstantiate(
            this IProxyFactory pf,
            string entityName,
            System.Type persistentClass,
            HashSet <System.Type> interfaces,
            MethodInfo getIdentifierMethod,
            MethodInfo setIdentifierMethod,
            IAbstractComponentType componentIdType,
            bool isClassProxy)
        {
            if (pf is AbstractProxyFactory apf)
            {
                apf.PostInstantiate(
                    entityName,
                    persistentClass,
                    interfaces,
                    getIdentifierMethod,
                    setIdentifierMethod,
                    componentIdType,
                    isClassProxy);
            }
            else
            {
#pragma warning disable 618
                pf.PostInstantiate(
                    entityName,
                    persistentClass,
                    interfaces,
                    getIdentifierMethod,
                    setIdentifierMethod,
                    componentIdType);
#pragma warning restore 618
            }
        }
Пример #2
0
        protected override IProxyFactory BuildProxyFactory(PersistentClass persistentClass, IGetter idGetter,
                                                           ISetter idSetter)
        {
            bool needAccesorCheck = true;             // NH specific (look the comment below)

            // determine the id getter and setter methods from the proxy interface (if any)
            // determine all interfaces needed by the resulting proxy
            var proxyInterfaces = new HashSet <System.Type> {
                typeof(INHibernateProxy)
            };

            System.Type _mappedClass    = persistentClass.MappedClass;
            System.Type _proxyInterface = persistentClass.ProxyInterface;

            if (_proxyInterface != null && !_mappedClass.Equals(_proxyInterface))
            {
                if (!_proxyInterface.IsInterface)
                {
                    throw new MappingException("proxy must be either an interface, or the class itself: " + EntityName);
                }
                needAccesorCheck = false;                 // NH (the proxy is an interface all properties can be overridden)
                proxyInterfaces.Add(_proxyInterface);
            }

            if (_mappedClass.IsInterface)
            {
                needAccesorCheck = false;                 // NH (the mapped class is an interface all properties can be overridden)
                proxyInterfaces.Add(_mappedClass);
            }

            foreach (Subclass subclass in persistentClass.SubclassIterator)
            {
                System.Type subclassProxy = subclass.ProxyInterface;
                System.Type subclassClass = subclass.MappedClass;
                if (subclassProxy != null && !subclassClass.Equals(subclassProxy))
                {
                    if (!subclassProxy.IsInterface)
                    {
                        throw new MappingException("proxy must be either an interface, or the class itself: " + subclass.EntityName);
                    }
                    proxyInterfaces.Add(subclassProxy);
                }
            }

            /*
             * NH Different Implementation (for Error logging):
             * - Check if the logger is enabled
             * - Don't need nothing to check if the mapped-class or proxy is an interface
             */
            if (log.IsErrorEnabled() && needAccesorCheck)
            {
                LogPropertyAccessorsErrors(persistentClass);
            }
            /**********************************************************/

            MethodInfo idGetterMethod = idGetter == null ? null : idGetter.Method;
            MethodInfo idSetterMethod = idSetter == null ? null : idSetter.Method;

            MethodInfo proxyGetIdentifierMethod = idGetterMethod == null || _proxyInterface == null ? null :
                                                  ReflectHelper.TryGetMethod(_proxyInterface, idGetterMethod);

            MethodInfo proxySetIdentifierMethod = idSetterMethod == null || _proxyInterface == null ? null :
                                                  ReflectHelper.TryGetMethod(_proxyInterface, idSetterMethod);

            IProxyFactory pf = BuildProxyFactoryInternal(persistentClass, idGetter, idSetter);

            try
            {
                pf.PostInstantiate(EntityName, _mappedClass, proxyInterfaces, proxyGetIdentifierMethod, proxySetIdentifierMethod,
                                   persistentClass.HasEmbeddedIdentifier ? (IAbstractComponentType)persistentClass.Identifier.Type: null);
            }
            catch (HibernateException he)
            {
                log.Warn(he, "could not create proxy factory for:{0}", EntityName);
                pf = null;
            }
            return(pf);
        }
		protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
		                                  ISessionFactoryImplementor factory)
		{
			this.factory = factory;
			dialect = factory.Dialect;
			this.cache = cache;
			//sqlExceptionConverter = factory.SQLExceptionConverter;

			entityMetamodel = new EntityMetamodel(persistentClass, factory);

			// CLASS
			mappedClass = persistentClass.MappedClass;

			sqlWhereString = persistentClass.Where;
			sqlWhereStringTemplate = sqlWhereString == null
			                         	?
			                         null
			                         	:
			                         Template.RenderWhereStringTemplate(sqlWhereString, Dialect, factory.SQLFunctionRegistry);

			batchSize = persistentClass.BatchSize;
			hasSubselectLoadableCollections = persistentClass.HasSubselectLoadableCollections;
			constructor = ReflectHelper.GetDefaultConstructor(mappedClass);

			// 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 (!entityMetamodel.IsAbstract && constructor == null)
			{
				throw new MappingException("The mapped class " + mappedClass.FullName +
				                           " must declare a default (no-arg) constructor.");
			}

			// IDENTIFIER
			hasEmbeddedIdentifier = persistentClass.HasEmbeddedIdentifier;
			IValue idValue = persistentClass.Identifier;

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

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

			if (persistentClass.HasIdentifierProperty && prox != null)
			{
				Mapping.Property idProperty = persistentClass.IdentifierProperty;
				proxyGetIdentifierMethod = idProperty.GetGetter(prox).Method;
				proxySetIdentifierMethod = idProperty.GetSetter(prox).Method;
			}

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

			// IDENTIFIER 

			identifierColumnSpan = persistentClass.Identifier.ColumnSpan;
			rootTableKeyColumnNames = new string[identifierColumnSpan];
			identifierAliases = new string[identifierColumnSpan];

			loaderName = persistentClass.LoaderName;

			int i = 0;
			foreach (Column col in idValue.ColumnCollection)
			{
				rootTableKeyColumnNames[i] = col.GetQuotedName(factory.Dialect);
				identifierAliases[i] = col.GetAlias(Dialect, persistentClass.RootTable);
				i++;
			}

			// VERSION:

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

			if (persistentClass.IsVersioned)
			{
				versionGetter = persistentClass.Version.GetGetter(mappedClass);
				versionType = (IVersionType) persistentClass.Version.Type;
			}
			else
			{
				versionGetter = null;
				versionType = null;
			}

			// PROPERTIES 

			getters = new IGetter[hydrateSpan];
			setters = new ISetter[hydrateSpan];
			string[] setterNames = new string[hydrateSpan];
			string[] getterNames = new string[hydrateSpan];
			System.Type[] classes = new System.Type[hydrateSpan];

			i = 0;

			// NH: reflection optimizer works with custom accessors
			//bool foundCustomAccessor = false;

			foreach (Mapping.Property prop in persistentClass.PropertyClosureCollection)
			{
				//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;
				classes[i] = getters[i].ReturnType;

				string propertyName = prop.Name;
				gettersByPropertyName[propertyName] = getters[i];
				settersByPropertyName[propertyName] = setters[i];

				i++;
			}

			// PROPERTIES (FROM ABSTRACTENTITYPERSISTER SUBCLASSES)
			propertyColumnNames = new string[HydrateSpan][];
			propertyColumnAliases = new string[HydrateSpan][];
			propertyColumnSpans = new int[HydrateSpan];
			propertyColumnFormulaTemplates = new string[HydrateSpan][];
			propertyColumnUpdateable = new bool[HydrateSpan][];
			propertyColumnInsertable = new bool[HydrateSpan][];
			propertyUniqueness = new bool[HydrateSpan];

			HashedSet thisClassProperties = new HashedSet();
			i = 0;
			bool foundFormula = false;

			foreach (Mapping.Property prop in persistentClass.PropertyClosureCollection)
			{
				thisClassProperties.Add(prop);

				int span = prop.ColumnSpan;
				propertyColumnSpans[i] = span;
				string[] colNames = new string[span];
				string[] colAliases = new string[span];
				string[] templates = new string[span];

				int k = 0;
				foreach (ISelectable thing in prop.ColumnCollection)
				{
					colAliases[k] = thing.GetAlias(factory.Dialect, prop.Value.Table);
					if (thing.IsFormula)
					{
						foundFormula = true;
						templates[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					else
					{
						colNames[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					k++;
				}
				propertyColumnNames[i] = colNames;
				propertyColumnFormulaTemplates[i] = templates;
				propertyColumnAliases[i] = colAliases;
				propertyColumnInsertable[i] = prop.Value.ColumnInsertability;
				propertyColumnUpdateable[i] = prop.Value.ColumnUpdateability;
				propertyUniqueness[i] = prop.Value.IsUnique;

				i++;
			}

			hasFormulaProperties = foundFormula;

			// NH: reflection optimizer works with custom accessors
			if (Environment.UseReflectionOptimizer)
			{
				optimizer = Environment.BytecodeProvider.GetReflectionOptimizer(MappedClass, Getters, Setters);
			}

			// SUBCLASS PROPERTY CLOSURE

			ArrayList columns = new ArrayList(); //this.subclassColumnClosure
			ArrayList aliases = new ArrayList();
			ArrayList formulaAliases = new ArrayList();
			ArrayList formulaTemplates = new ArrayList();
			ArrayList types = new ArrayList(); //this.subclassPropertyTypeClosure
			ArrayList names = new ArrayList(); //this.subclassPropertyNameClosure
			ArrayList subclassTemplates = new ArrayList();
			ArrayList propColumns = new ArrayList(); //this.subclassPropertyColumnNameClosure
			ArrayList joinedFetchesList = new ArrayList(); //this.subclassPropertyEnableJoinedFetch
			ArrayList cascades = new ArrayList();
			ArrayList definedBySubclass = new ArrayList(); // this.propertyDefinedOnSubclass
			ArrayList formulas = new ArrayList();
			ArrayList propNullables = new ArrayList();

			foreach (Mapping.Property prop in persistentClass.SubclassPropertyClosureCollection)
			{
				names.Add(prop.Name);
				bool isDefinedBySubclass = !thisClassProperties.Contains(prop);
				definedBySubclass.Add(isDefinedBySubclass);
				propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct?
				types.Add(prop.Type);

				string[] cols = new string[prop.ColumnSpan];
				string[] forms = new string[prop.ColumnSpan];
				int[] colnos = new int[prop.ColumnSpan];
				int[] formnos = new int[prop.ColumnSpan];
				int l = 0;

				foreach (ISelectable thing in prop.ColumnCollection)
				{
					if (thing.IsFormula)
					{
						string template = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						formnos[l] = formulaTemplates.Count;
						colnos[l] = -1;
						formulaTemplates.Add(template);
						forms[l] = template;
						formulas.Add(thing.GetText(factory.Dialect));
						formulaAliases.Add(thing.GetAlias(factory.Dialect));
						// TODO H3: formulasLazy.add( lazy );
					}
					else
					{
						String colName = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						colnos[l] = columns.Count; //before add :-)
						formnos[l] = -1;
						columns.Add(colName);
						cols[l] = colName;
						aliases.Add(thing.GetAlias(factory.Dialect, prop.Value.Table));
						// TODO H3: columnsLazy.add( lazy );
						// TODO H3: columnSelectables.add( new Boolean( prop.isSelectable() ) );
					}
					l++;
				}

				propColumns.Add(cols);
				subclassTemplates.Add(forms);
				//propColumnNumbers.Add( colnos );
				//propFormulaNumbers.Add( formnos );

				joinedFetchesList.Add(prop.Value.FetchMode);
				cascades.Add(prop.CascadeStyle);
			}

			subclassColumnClosure = (string[]) columns.ToArray(typeof(string));
			subclassFormulaClosure = (string[]) formulas.ToArray(typeof(string));
			subclassFormulaTemplateClosure = (string[]) formulaTemplates.ToArray(typeof(string));
			subclassPropertyTypeClosure = (IType[]) types.ToArray(typeof(IType));
			subclassColumnAliasClosure = (string[]) aliases.ToArray(typeof(string));
			subclassFormulaAliasClosure = (string[]) formulaAliases.ToArray(typeof(string));
			subclassPropertyNameClosure = (string[]) names.ToArray(typeof(string));
			subclassPropertyNullabilityClosure = (bool[]) propNullables.ToArray(typeof(bool));
			subclassPropertyFormulaTemplateClosure = ArrayHelper.To2DStringArray(subclassTemplates);
			subclassPropertyColumnNameClosure = (string[][]) propColumns.ToArray(typeof(string[]));

			subclassPropertyCascadeStyleClosure = new Cascades.CascadeStyle[cascades.Count];
			int m = 0;
			foreach (Cascades.CascadeStyle cs in cascades)
			{
				subclassPropertyCascadeStyleClosure[m++] = cs;
			}

			subclassPropertyFetchModeClosure = new FetchMode[joinedFetchesList.Count];
			m = 0;
			foreach (FetchMode qq in joinedFetchesList)
			{
				subclassPropertyFetchModeClosure[m++] = qq;
			}

			propertyDefinedOnSubclass = new bool[definedBySubclass.Count];
			m = 0;
			foreach (bool val in definedBySubclass)
			{
				propertyDefinedOnSubclass[m++] = val;
			}

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

			// PROXIES
			concreteProxyClass = persistentClass.ProxyInterface;
			bool 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 persistentClass.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;
			}

			// Handle any filters applied to the class level
			filterHelper = new FilterHelper(persistentClass.FilterMap, factory.Dialect, factory.SQLFunctionRegistry);
		}
		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;
			}
		}