From: Paul H. <pha...@us...> - 2005-03-01 16:25:35
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5548/nhibernate/src/NHibernate/Loader Modified Files: AbstractEntityLoader.cs CollectionLoader.cs EntityLoader.cs Loader.cs OneToManyLoader.cs OuterJoinLoader.cs SimpleEntityLoader.cs Added Files: SqlLoader.cs Log Message: Various refactorings on the way to 2.1 querying capability Index: AbstractEntityLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/AbstractEntityLoader.cs,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** AbstractEntityLoader.cs 31 Dec 2004 20:57:25 -0000 1.13 --- AbstractEntityLoader.cs 1 Mar 2005 16:24:47 -0000 1.14 *************** *** 1,4 **** --- 1,5 ---- using System; using System.Collections; + using NHibernate.Collection; using NHibernate.Engine; using NHibernate.Persister; *************** *** 12,16 **** --- 13,20 ---- { private ILoadable persister; + private ICollectionPersister collectionPersister; + private int collectionOwner; private string alias; + private string[] aliases; /// <summary> *************** *** 174,177 **** --- 178,261 ---- } + /// <summary> + /// + /// </summary> + /// <param name="associations"></param> + protected void InitClassPersisters( IList associations ) + { + int joins = CountClassPersisters( associations ); + + collectionOwner = -1; // if no collection found + classPersisters = new ILoadable[ joins + 1 ]; + owners = new int[ joins + 1 ]; + aliases = new string[ joins + 1 ]; + LockModeArray = CreateLockModeArray( joins + 1, LockMode.None ); + int i = 0; + foreach( OuterJoinableAssociation oj in associations ) + { + object subpersister = oj.Joinable; + if ( subpersister is ILoadable ) + { + classPersisters[ i ] = (ILoadable) subpersister; + owners[ i ] = ToOwner( oj, joins, oj.IsOneToOne ); + aliases[ i ] = oj.Subalias; + if ( oj.JoinType == JoinType.InnerJoin ) + { + AddAllToPropertySpaces( classPersisters[ i ].PropertySpaces ); + } + i++; + } + else + { + IQueryableCollection collPersister = (IQueryableCollection) subpersister; + // TODO: ?? suppress initialization of collections with a where condition + if ( oj.JoinType == JoinType.LeftOuterJoin ) + { + collectionPersister = collPersister; + collectionOwner = ToOwner( oj, joins, true ); + } + else + { + AddToPropertySpaces( collPersister.CollectionSpace ) ; + } + + if ( collPersister.IsOneToMany ) + { + classPersisters[ i ] = (ILoadable) collPersister.ElementPersister; + aliases[ i ] = oj.Subalias; + i++; + } + } + } + classPersisters[ joins ] = persister; + owners[ joins ] = -1; + aliases[ joins ] = alias; + + if ( ArrayHelper.IsAllNegative( owners ) ) + { + owners = null; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="spaces"></param> + protected void AddAllToPropertySpaces( object[] spaces ) + { + for ( int i = 0; i < spaces.Length; i++ ) + { + AddToPropertySpaces( spaces[ i ] ); + } + } + + /// <summary> + /// + /// </summary> + /// <param name="space"></param> + protected void AddToPropertySpaces( object space ) + { + throw new NotSupportedException( "only criteria queries need to autoflush" ); + } } } \ No newline at end of file Index: OneToManyLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/OneToManyLoader.cs,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** OneToManyLoader.cs 31 Dec 2004 20:57:56 -0000 1.13 --- OneToManyLoader.cs 1 Mar 2005 16:24:48 -0000 1.14 *************** *** 15,19 **** public class OneToManyLoader : OuterJoinLoader, ICollectionInitializer { ! private CollectionPersister collectionPersister; private IType idType; --- 15,19 ---- public class OneToManyLoader : OuterJoinLoader, ICollectionInitializer { ! private IQueryableCollection collectionPersister; private IType idType; *************** *** 21,35 **** /// /// </summary> ! /// <param name="mappingDefault"></param> ! /// <param name="path"></param> ! /// <param name="table"></param> ! /// <param name="foreignKeyColumns"></param> ! /// <returns></returns> ! protected override bool EnableJoinedFetch( bool mappingDefault, string path, string table, string[ ] foreignKeyColumns ) { - return mappingDefault && ( - !table.Equals( collectionPersister.QualifiedTableName ) || - !ArrayHelper.Equals( foreignKeyColumns, collectionPersister.KeyColumnNames ) - ); } --- 21,28 ---- /// /// </summary> ! /// <param name="collPersister"></param> ! /// <param name="factory"></param> ! public OneToManyLoader( IQueryableCollection collPersister, ISessionFactoryImplementor factory ) : this( collPersister, 1, factory ) { } *************** *** 38,51 **** /// </summary> /// <param name="collPersister"></param> /// <param name="factory"></param> ! public OneToManyLoader( CollectionPersister collPersister, ISessionFactoryImplementor factory ) : base( factory.Dialect ) { collectionPersister = collPersister; idType = collectionPersister.KeyType; ! ILoadable persister = ( ILoadable ) factory.GetPersister( ! ( ( EntityType ) collPersister.ElementType ).PersistentClass ); ! string alias = ToAlias( collectionPersister.QualifiedTableName, 0 ); SqlString whereSqlString = null; --- 31,45 ---- /// </summary> /// <param name="collPersister"></param> + /// <param name="batchSize"></param> /// <param name="factory"></param> ! public OneToManyLoader( IQueryableCollection collPersister, int batchSize, ISessionFactoryImplementor factory ) : base( factory.Dialect ) { collectionPersister = collPersister; idType = collectionPersister.KeyType; ! //ILoadable persister = ( ILoadable ) factory.GetPersister( ( ( EntityType ) collPersister.ElementType ).AssociatedClass ); ! ILoadable persister = ( ILoadable ) collPersister.ElementPersister; ! string alias = ToAlias( collectionPersister.TableName, 0 ); SqlString whereSqlString = null; *************** *** 65,69 **** } - JoinFragment ojf = OuterJoins( associations ); --- 59,62 ---- *************** *** 71,75 **** selectBuilder.SetSelectClause( ! collectionPersister.SelectClauseFragment( alias ) + ( joins == 0 ? String.Empty : "," + SelectString( associations ) ) + ", " + --- 64,68 ---- selectBuilder.SetSelectClause( ! collectionPersister.SelectFragment( alias ).ToString() + ( joins == 0 ? String.Empty : "," + SelectString( associations ) ) + ", " + *************** *** 116,121 **** } /// <summary></summary> ! protected override CollectionPersister CollectionPersister { get { return collectionPersister; } --- 109,130 ---- } + /// <summary> + /// + /// </summary> + /// <param name="mappingDefault"></param> + /// <param name="path"></param> + /// <param name="table"></param> + /// <param name="foreignKeyColumns"></param> + /// <returns></returns> + protected override bool EnableJoinedFetch( bool mappingDefault, string path, string table, string[ ] foreignKeyColumns ) + { + return mappingDefault && ( + !table.Equals( collectionPersister.TableName ) || + !ArrayHelper.Equals( foreignKeyColumns, collectionPersister.KeyColumnNames ) + ); + } + /// <summary></summary> ! protected override ICollectionPersister CollectionPersister { get { return collectionPersister; } Index: CollectionLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/CollectionLoader.cs,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** CollectionLoader.cs 31 Dec 2004 20:57:25 -0000 1.12 --- CollectionLoader.cs 1 Mar 2005 16:24:48 -0000 1.13 *************** *** 15,19 **** public class CollectionLoader : OuterJoinLoader, ICollectionInitializer { ! private CollectionPersister collectionPersister; private IType idType; --- 15,19 ---- public class CollectionLoader : OuterJoinLoader, ICollectionInitializer { ! private ICollectionPersister collectionPersister; private IType idType; *************** *** 23,31 **** /// <param name="persister"></param> /// <param name="factory"></param> ! public CollectionLoader( CollectionPersister persister, ISessionFactoryImplementor factory ) : base( factory.Dialect ) { idType = persister.KeyType; ! string alias = ToAlias( persister.QualifiedTableName, 0 ); //TODO: H2.0.3 the whereString is appended with the " and " - I don't think --- 23,31 ---- /// <param name="persister"></param> /// <param name="factory"></param> ! public CollectionLoader( IQueryableCollection persister, ISessionFactoryImplementor factory ) : base( factory.Dialect ) { idType = persister.KeyType; ! string alias = ToAlias( persister.TableName, 0 ); //TODO: H2.0.3 the whereString is appended with the " and " - I don't think *************** *** 51,58 **** SqlSelectBuilder selectBuilder = new SqlSelectBuilder( factory ); selectBuilder.SetSelectClause( ! persister.SelectClauseFragment( alias ) + ( joins == 0 ? String.Empty : ", " + SelectString( associations ) ) ) ! .SetFromClause( persister.QualifiedTableName, alias ) .SetWhereClause( alias, persister.KeyColumnNames, persister.KeyType ) .SetOuterJoins( ojf.ToFromFragmentString, ojf.ToWhereFragmentString ); --- 51,58 ---- SqlSelectBuilder selectBuilder = new SqlSelectBuilder( factory ); selectBuilder.SetSelectClause( ! persister.SelectFragment( alias ).ToString() + ( joins == 0 ? String.Empty : ", " + SelectString( associations ) ) ) ! .SetFromClause( persister.TableName, alias ) .SetWhereClause( alias, persister.KeyColumnNames, persister.KeyType ) .SetOuterJoins( ojf.ToFromFragmentString, ojf.ToWhereFragmentString ); *************** *** 83,87 **** /// <summary></summary> ! protected override CollectionPersister CollectionPersister { get { return collectionPersister; } --- 83,87 ---- /// <summary></summary> ! protected override ICollectionPersister CollectionPersister { get { return collectionPersister; } --- NEW FILE: SqlLoader.cs --- using System; using System.Data; using System.Collections; using System.Text; using Iesi.Collections; using NHibernate.Engine; using NHibernate.Persister; using NHibernate.SqlCommand; using NHibernate.Hql; using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Loader { /// <summary> /// Summary description for SqlLoader. /// </summary> public class SqlLoader : OuterJoinLoader { private int parameterCount = 0; private IDictionary namedParameters = new Hashtable(4); private string sqlQuery; private IDictionary alias2Persister; private string[] aliases; private ISet querySpaces = new HashedSet(); //private IType[] resultTypes; #region Constructors /// <summary> /// /// </summary> /// <param name="aliases"></param> /// <param name="persisters"></param> /// <param name="factory"></param> /// <param name="sqlQuery"></param> /// <param name="additionalQuerySpaces"></param> public SqlLoader( string[] aliases, ISqlLoadable[] persisters, ISessionFactoryImplementor factory, string sqlQuery, ICollection additionalQuerySpaces) : base( factory.Dialect ) { this.sqlQuery = sqlQuery; this.aliases = aliases; alias2Persister = new Hashtable(); IList resultTypeList = new ArrayList(); for (int i = 0; i < persisters.Length; i++ ) { ISqlLoadable persister = persisters[i]; alias2Persister.Add( aliases[i], persister ); // TODO: Does not consider any other tables referenced in the query querySpaces.AddAll( persister.PropertySpaces ) ; resultTypeList.Add( persister.Type ); } if ( additionalQuerySpaces != null ) querySpaces.AddAll( additionalQuerySpaces ); //resultTypes = (IType[]) resultTypeList.ToArray() ; RenderStatement( persisters ) ; PostInstantiate(); } #endregion #region Property methods /// <summary> /// /// </summary> public ISet QuerySpaces { get { return querySpaces; } } #endregion #region Private methods private void RenderStatement( ILoadable[] persisters ) { int loadables = persisters.Length; Persisters = persisters; Suffixes = GenerateSuffixes( loadables ) ; LockModeArray = CreateLockModeArray( loadables, LockMode.None ); sqlQuery = SubstituteParams( SubstituteBrackets( sqlQuery ) ); } private string SubstituteParams(string sqlQuery) { string sqlString = sqlQuery; StringBuilder result = new StringBuilder(); int left, right; for ( int curr = 0; curr < sqlString.Length; curr = right + 1 ) { if ( ( left = sqlString.IndexOf( ParserHelper.HqlVariablePrefix, curr ) ) < 0 ) { result.Append( sqlString.Substring( curr ) ); break; } result.Append( sqlString.Substring( curr, left ) ); // Find the first place of a HqlSeparator character right = sqlString.IndexOfAny( ParserHelper.HqlSeparators.ToCharArray(), left + 1 ); // Did we find one? bool foundSeparator = right > 0; int chopLocation = -1; if ( right < 0 ) { chopLocation = sqlString.Length; } else { chopLocation = right; } string param = sqlString.Substring( left + 1, chopLocation ); AddNamedParameter( param ); result.Append( "?" ); if ( foundSeparator ) { result.Append( sqlString.Substring( right, 1 ) ); } else { break; } } return result.ToString(); } private int PersisterIndex( string aliasName ) { for ( int i = 0; i < aliases.Length; i++ ) { if ( aliasName == aliases[i] ) { return i; } } return -1; } private ISqlLoadable GetPersisterByResultAlias( string aliasName ) { // NB This return the dictionary object I think not the value. return (ISqlLoadable) alias2Persister[ aliasName ]; } #endregion #region Protected methods /// <summary> /// Bind named parameters to the <c>IDbCommand</c> /// </summary> /// <param name="st">The <see cref="IDbCommand"/> that contains the parameters.</param> /// <param name="namedParams">The named parameters (key) and the values to set.</param> /// <param name="session">The <see cref="ISession"/> this Loader is using.</param> /// <param name="start"></param> /// <remarks> /// Assumes that all types are of span 1 /// </remarks> protected override int BindNamedParameters( IDbCommand st, IDictionary namedParams, int start, ISessionImplementor session ) { if ( namedParameters != null ) { int result = 0; // Assumes that types are all of span 1 foreach( DictionaryEntry de in namedParams ) { string name = (string) de.Key; TypedValue typedval = (TypedValue) de.Value; IType type = typedval.Type; int[] locs = GetNamedParameterLocs( name ); for ( int i = 0; i < locs.Length; i++ ) { type.NullSafeSet( st, typedval.Value, locs[i] + start, session ); } result += locs.Length; } return result; } else return 0; } /// <summary> /// /// </summary> /// <param name="row"></param> /// <param name="rs"></param> /// <param name="session"></param> /// <returns></returns> protected override object GetResultColumnOrRow( object[ ] row, IDataReader rs, ISessionImplementor session ) { if ( Persisters.Length == 1 ) return row[ row.Length - 1 ]; else return row; } /// <summary> /// /// </summary> /// <param name="name"></param> /// <returns></returns> protected int[] GetNamedParameterLocs( string name ) { object o = namedParameters[ name ]; if ( o == null ) { throw new QueryException( String.Format( "Named parameter does not appear in query: {0} ", name ) ); } if ( o is int) { return new int[] { (int) o }; } else { return ArrayHelper.ToIntArray( (IList) o ); } } #endregion #region Public methods /// <summary> /// /// </summary> /// <param name="session"></param> /// <param name="queryParameters"></param> /// <returns></returns> public IList List( ISessionImplementor session, QueryParameters queryParameters ) { // TODO: Uncomment once //return List( session, queryParameters, querySpaces, resultTypes ) ; return null ; } // Inspired by the parsing done in TJDO // TODO: Should record how many properties we have referred to - and throw exception if we don't get them all aka AbstractQueryImpl /// <summary> /// /// </summary> /// <param name="sqlQuery"></param> /// <returns></returns> public string SubstituteBrackets( string sqlQuery ) { string sqlString = sqlQuery; StringBuilder result = new StringBuilder(); int left, right; // replace {....} with corresponding column aliases for (int curr = 0; curr < sqlString.Length; curr = right + 1) { if ( (left = sqlString.IndexOf( '{', curr ) ) < 0 ) { result.Append( sqlString.Substring( curr ) ) ; break; } result.Append( sqlString.Substring( curr, left ) ); if ( ( right = sqlString.IndexOf( '}', left + 1 ) ) < 0 ) { throw new QueryException( "Unmatched braces for alias path" ); } string aliasPath = sqlString.Substring( left + 1, right ); int firstDot = aliasPath.IndexOf( '.' ); string aliasName = firstDot == 1 ? aliasPath : aliasPath.Substring( 0, firstDot ) ; ISqlLoadable currentPersister = GetPersisterByResultAlias( aliasName ) ; if ( currentPersister == null ) { // TODO: Do we throw this or pass through as per Hibernate to allow for escape sequences as per HB-898 throw new QueryException( string.Format( "Alias [{0}] does not correspond to any of the supplied return aliases = {1}", aliasName, aliases ) ); //result.Append( "{" + aliasPath + "}" ); //continue; } int currentPersisterIndex = PersisterIndex( aliasName ); if ( firstDot == -1 ) { result.Append( aliasPath ) ; } else { if ( aliasName != aliases[ currentPersisterIndex ] ) { throw new QueryException( string.Format( "Alias [{0}] does not correspond to return alias {1}.", aliasName, aliases[ currentPersisterIndex ] ) ); } string propertyName = aliasPath.Substring( firstDot + 1 ); if ( "*".Equals( propertyName ) ) { result.Append( currentPersister.SelectFragment( aliasName, Suffixes[ currentPersisterIndex ] ) ); } else { // Here it would be nice just to be able to do result.Append( getAliasFor( currentPersister, propertyName )) // but that requires more exposure of the internal maps of the persister... // but it should be possible as propertyname should be unique for all persisters string[] columnAliases; /* if ( AbstractEntityPersister.ENTITY_CLASS.Equals( propertyName ) { columnAliases = new string[1]; columnAliases[0] = currentPersister.GetDiscriminatorAlias( suffixes[ currentPersisterIndex ] ) ; } else */ columnAliases = currentPersister.GetSubclassPropertyColumnAliases( propertyName, Suffixes[ currentPersisterIndex ] ); if ( columnAliases == null || columnAliases.Length == 0 ) { throw new QueryException( string.Format( "No column name found for property [{0}]", propertyName ) ); } if ( columnAliases.Length != 1 ) { throw new QueryException( string.Format( "SQL queries only support properties mapped to a single column. Property [{0}] is mapped to {1} columns.", propertyName, columnAliases.Length ) ); } result.Append( columnAliases[ 0 ] ) ; } } } // Possibly handle :something parameters for the query? return result.ToString(); } // NAMED PARAMETER SUPPORT, copy/pasted from QueryTranslator internal void AddNamedParameter( string name ) { // want the param index to start at 0 instead of 1 //int loc = ++parameterCount; int loc = parameterCount++; object o = namedParameters[ name ]; if( o == null ) { namedParameters.Add( name, loc ); } else if( o is int ) { ArrayList list = new ArrayList( 4 ); list.Add( o ); list.Add( loc ); namedParameters[ name ] = list; } else { ( ( ArrayList ) o ).Add( loc ); } } #endregion } } Index: OuterJoinLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/OuterJoinLoader.cs,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** OuterJoinLoader.cs 31 Dec 2004 20:57:56 -0000 1.17 --- OuterJoinLoader.cs 1 Mar 2005 16:24:48 -0000 1.18 *************** *** 3,6 **** --- 3,7 ---- using System.Text; using NHibernate.Collection; + using NHibernate.Dialect; using NHibernate.Engine; using NHibernate.Persister; *************** *** 12,16 **** { /// <summary></summary> ! public enum OuterJoinLoaderType { /// <summary></summary> --- 13,17 ---- { /// <summary></summary> ! public enum OuterJoinFetchStrategy { /// <summary></summary> *************** *** 37,45 **** protected static readonly ILoadable[ ] NoPersisters = new ILoadable[0]; ! private ILoadable[ ] classPersisters; private LockMode[ ] lockModeArray; private SqlString sqlString; private string[ ] suffixes; /// <summary> --- 38,52 ---- protected static readonly ILoadable[ ] NoPersisters = new ILoadable[0]; ! /// <summary></summary> ! protected ILoadable[ ] classPersisters; ! private LockMode[ ] lockModeArray; + /// <summary></summary> + protected int[] owners; + private SqlString sqlString; private string[ ] suffixes; + private Dialect.Dialect dialect; /// <summary> *************** *** 68,76 **** { /// <summary></summary> ! public ILoadable Subpersister; /// <summary></summary> public string[ ] ForeignKeyColumns; /// <summary></summary> public string Subalias; } --- 75,95 ---- { /// <summary></summary> ! public IJoinable Joinable; ! /// <summary></summary> ! public IQueryable Subpersister; /// <summary></summary> public string[ ] ForeignKeyColumns; /// <summary></summary> public string Subalias; + /// <summary></summary> + public string[] PrimaryKeyColumns; + /// <summary></summary> + public string TableName; + /// <summary></summary> + public int Owner; + /// <summary></summary> + public JoinType JoinType; + /// <summary></summary> + public bool IsOneToOne; } *************** *** 96,100 **** /// <param name="session"></param> /// <returns></returns> ! protected IList WalkCollectionTree( CollectionPersister persister, string alias, ISessionFactoryImplementor session ) { IList associations = new ArrayList(); --- 115,119 ---- /// <param name="session"></param> /// <returns></returns> ! protected IList WalkCollectionTree( IQueryableCollection persister, string alias, ISessionFactoryImplementor session ) { IList associations = new ArrayList(); *************** *** 107,111 **** EntityType etype = ( EntityType ) type; // we do NOT need to call this.EnableJoinedFetch() here ! if( AutoEager( persister.EnableJoinFetch, etype, session ) ) { string[ ] columns = StringHelper.Prefix( persister.ElementColumnNames, alias + StringHelper.Dot ); --- 126,130 ---- EntityType etype = ( EntityType ) type; // we do NOT need to call this.EnableJoinedFetch() here ! if( AutoEager( persister.EnableJoinedFetch, etype, session ) ) { string[ ] columns = StringHelper.Prefix( persister.ElementColumnNames, alias + StringHelper.Dot ); *************** *** 143,147 **** ISessionFactoryImplementor session ) { ! ILoadable subpersister = ( ILoadable ) session.GetPersister( type.PersistentClass ); // to avoid navigating back up bidirectional associations (and circularities) --- 162,166 ---- ISessionFactoryImplementor session ) { ! IQueryable subpersister = ( IQueryable ) session.GetPersister( type.AssociatedClass ); // to avoid navigating back up bidirectional associations (and circularities) *************** *** 353,357 **** IAbstractComponentType act, string[ ] cols, ! CollectionPersister persister, string alias, IList associations, --- 372,376 ---- IAbstractComponentType act, string[ ] cols, ! IQueryableCollection persister, string alias, IList associations, *************** *** 379,383 **** string subpath = SubPath( path, propertyNames[ i ] ); bool autoEager = AutoEager( act.EnableJoinedFetch( i ), etype, session ); ! bool enable = EnableJoinedFetch( autoEager, subpath, persister.QualifiedTableName, range ); if( enable ) --- 398,402 ---- string subpath = SubPath( path, propertyNames[ i ] ); bool autoEager = AutoEager( act.EnableJoinedFetch( i ), etype, session ); ! bool enable = EnableJoinedFetch( autoEager, subpath, persister.TableName, range ); if( enable ) *************** *** 414,428 **** /// <param name="session"></param> /// <returns></returns> ! protected bool AutoEager( OuterJoinLoaderType config, EntityType type, ISessionFactoryImplementor session ) { ! if( config == OuterJoinLoaderType.Eager ) { return true; } ! if( config == OuterJoinLoaderType.Lazy ) { return false; } ! IClassPersister persister = session.GetPersister( type.PersistentClass ); return !persister.HasProxy || ( type.IsOneToOne && ( ( OneToOneType ) type ).IsNullable ); } --- 433,447 ---- /// <param name="session"></param> /// <returns></returns> ! protected bool AutoEager( OuterJoinFetchStrategy config, EntityType type, ISessionFactoryImplementor session ) { ! if( config == OuterJoinFetchStrategy.Eager ) { return true; } ! if( config == OuterJoinFetchStrategy.Lazy ) { return false; } ! IClassPersister persister = session.GetPersister( type.AssociatedClass ); return !persister.HasProxy || ( type.IsOneToOne && ( ( OneToOneType ) type ).IsNullable ); } *************** *** 524,528 **** /// <summary></summary> ! protected override CollectionPersister CollectionPersister { get { return null; } --- 543,547 ---- /// <summary></summary> ! protected override ICollectionPersister CollectionPersister { get { return null; } *************** *** 548,553 **** outerjoin.AddJoins( ! oj.Subpersister.FromJoinFragment( oj.Subalias, false, true ), ! oj.Subpersister.WhereJoinFragment( oj.Subalias, false, true ) ); } --- 567,572 ---- outerjoin.AddJoins( ! ( (IJoinable) oj.Subpersister).FromJoinFragment( oj.Subalias, false, true ), ! ( (IJoinable) oj.Subpersister).WhereJoinFragment( oj.Subalias, false, true ) ); } *************** *** 593,596 **** --- 612,652 ---- } + /// <summary> + /// + /// </summary> + /// <param name="associations"></param> + /// <returns></returns> + protected static int CountClassPersisters( IList associations ) + { + int result = 0; + foreach ( OuterJoinableAssociation oj in associations ) + { + if ( oj.Joinable.ConsumesAlias() ) + { + result++; + } + } + + return result; + } + + /// <summary> + /// + /// </summary> + /// <param name="oj"></param> + /// <param name="joins"></param> + /// <param name="dontIgnore"></param> + /// <returns></returns> + protected int ToOwner( OuterJoinableAssociation oj, int joins, bool dontIgnore ) + { + if ( dontIgnore ) + { + return oj.Owner == -1 ? joins : oj.Owner; //TODO: UGLY AS SIN! + } + else + { + return -1; + } + } } } \ No newline at end of file Index: SimpleEntityLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/SimpleEntityLoader.cs,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** SimpleEntityLoader.cs 31 Dec 2004 20:57:56 -0000 1.10 --- SimpleEntityLoader.cs 1 Mar 2005 16:24:48 -0000 1.11 *************** *** 20,25 **** private LockMode[ ] lockMode; - private string[ ] NoSuffix = new string[ ] {String.Empty}; - /// <summary> /// --- 20,23 ---- *************** *** 53,57 **** /// <summary></summary> ! protected override CollectionPersister CollectionPersister { get { return null; } --- 51,55 ---- /// <summary></summary> ! protected override ICollectionPersister CollectionPersister { get { return null; } Index: Loader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/Loader.cs,v retrieving revision 1.47 retrieving revision 1.48 diff -C2 -d -r1.47 -r1.48 *** Loader.cs 16 Feb 2005 20:14:38 -0000 1.47 --- Loader.cs 1 Mar 2005 16:24:48 -0000 1.48 *************** *** 3,6 **** --- 3,7 ---- using System.Data; using log4net; + using Iesi.Collections; using NHibernate.Collection; using NHibernate.Engine; *************** *** 25,28 **** --- 26,32 ---- private Dialect.Dialect dialect; + /// <summary></summary> + protected static readonly string[] NoSuffix = { string.Empty }; + /// <summary> /// *************** *** 82,86 **** /// return a non-null value /// </summary> ! protected abstract CollectionPersister CollectionPersister { get; } /// <summary> --- 86,90 ---- /// return a non-null value /// </summary> ! protected abstract ICollectionPersister CollectionPersister { get; } /// <summary> *************** *** 123,126 **** --- 127,142 ---- } + /// <summary> + /// + /// </summary> + /// <param name="session"></param> + /// <param name="queryParameters"></param> + /// <returns></returns> + protected IList DoList( ISessionImplementor session, QueryParameters queryParameters ) + { + // HACK Call DoFind as DoQuery is 2.1 + return DoFindAndInitializeNonLazyCollections( session, queryParameters, null, null, null, null, true ); + } + // This method is called DoQueryAndInitializeNonLazyCollections in H2.1, // since DoFind is called DoQuery and is split into several smaller methods. *************** *** 154,157 **** --- 170,204 ---- /// <summary> + /// + /// </summary> + /// <param name="resultSet"></param> + /// <param name="session"></param> + /// <param name="queryParameters"></param> + /// <param name="returnProxies"></param> + /// <returns></returns> + protected object LoadSingleRow( IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, bool returnProxies ) + { + int cols = Persisters.Length; + IList hydratedObjects = cols == 0 ? null : new ArrayList(); + object result = GetRowFromResultSet( resultSet, session, queryParameters, hydratedObjects, null, null, new Key[cols], returnProxies ); + + InitializeEntitiesAndCollections( hydratedObjects, resultSet, session ); + session.InitializeNonLazyCollections( ); + return result; + } + + private object GetRowFromResultSet( IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, IList hydratedObjects, object optionalObject, object optionalId, Key[] keys, bool returnProxies ) + { + ILoadable[] persisters = Persisters; + int cols = persisters.Length; + ICollectionPersister collectionPersister = CollectionPersister; + int collectionOwner = CollectionOwner; + string[] suffixes = Suffixes; + LockMode[] lockModeArray = GetLockModes( queryParameters.LockModes ); + + return null; + } + + /// <summary> /// Execute an SQL query and attempt to instantiate instances of the class mapped by the given /// persister from each row of the <c>IDataReader</c>. *************** *** 183,187 **** ILoadable[ ] persisters = Persisters; int cols = persisters.Length; ! CollectionPersister collectionPersister = this.CollectionPersister; int collectionOwner = this.CollectionOwner; bool returnsEntities = cols > 0; --- 230,234 ---- ILoadable[ ] persisters = Persisters; int cols = persisters.Length; ! ICollectionPersister collectionPersister = this.CollectionPersister; int collectionOwner = this.CollectionOwner; bool returnsEntities = cols > 0; *************** *** 321,325 **** --- 368,403 ---- } + return results; + } + + private void InitializeEntitiesAndCollections( IList hydratedObjects, object resultSetId, ISessionImplementor session ) + { + if ( Persisters.Length > 0 ) + { + int hydratedObjectsSize = hydratedObjects.Count; + if ( log.IsInfoEnabled ) + { + log.Info( string.Format( "total objects hydrated: ", hydratedObjectsSize ) ); + } + for ( int i = 0; i < hydratedObjectsSize; i++ ) + { + session.InitializeEntity( hydratedObjects[ i ] ); + } + } + ICollectionPersister collectionPersister = CollectionPersister; + if ( collectionPersister != null ) + { + // this is a query and we are loading multiple instances of the same collection role + //session.EndLoadingCollections( collectionPersister, resultSetId ); + } + } + /// <summary> + /// + /// </summary> + /// <param name="results"></param> + /// <returns></returns> + protected IList ResultList( IList results ) + { return results; } *************** *** 852,855 **** --- 930,976 ---- /// <summary> + /// + /// </summary> + /// <param name="session"></param> + /// <param name="queryParameters"></param> + /// <param name="querySpaces"></param> + /// <param name="resultTypes"></param> + /// <returns></returns> + protected IList List( + ISessionImplementor session, + QueryParameters queryParameters, + ISet querySpaces, + IType[] resultTypes ) + { + ISessionFactoryImplementor factory = session.Factory; + // TODO: Uncomment when QueryCache implemented + /* + bool cacheable = factory.IsQueryCacheable && queryParameters.IsCacheable; + + if ( cacheable ) + { + QueryCache queryCache = factory.GetQueryCache( queryParameters.CacheRegion ) ; + QueryKey key = new QueryKey( SqlString, queryParameters ); + IList result = null; + if ( !queryParameters.IsForceCacheRefresh ) + { + result = queryCache.Get( key, resultTypes, querySpaces, session ); + } + if ( result == null ) + { + result = DoList( session, queryParameters ); + queryCache.Add( key, resultTypes, result, session ); + } + } + else + { + return DoList( session, queryParameters ); + } + */ + + return Find( session, queryParameters, true ); + } + + /// <summary> /// Called by subclasses that implement queries. /// </summary> *************** *** 915,919 **** --- 1036,1076 ---- } + /// <summary> + /// Generate a nice alias for the given class name or collection role + /// name and unique integer. Subclasses do <em>not</em> have to use + /// aliases of this form. + /// </summary> + /// <param name="length"></param> + /// <returns>an alias of the form <c>foo1_</c></returns> + protected static string[] GenerateSuffixes(int length) + { + if (length==0) return NoSuffix; + + string[] suffixes = new string[ length ]; + for ( int i = 0; i< length; i++ ) + { + suffixes[ i ] = i.ToString( ) + StringHelper.Underscore; + } + return suffixes; + } + /// <summary> + /// Generate a nice alias for the given class name or collection role + /// name and unique integer. Subclasses do <em>not</em> have to use + /// aliases of this form. + /// </summary> + /// <param name="description"></param> + /// <param name="unique"></param> + /// <returns>an alias of the form <c>foo1_</c></returns> + protected static string GenerateAlias( string description, int unique ) + { + //return new Alias( 10, unique.ToString() + StringHelper.Underscore ) + // .ToAliasString( StringHelper.Unqualify( description ).ToLower(), Dialect ); + + string alias = StringHelper.Unqualify( description ).ToLower().Replace( "$", "_" ); + int len = Math.Min( 10, alias.Length ); + + return alias.Substring( 0, len ) + unique.ToString() + StringHelper.Underscore; + } } } \ No newline at end of file Index: EntityLoader.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Loader/EntityLoader.cs,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** EntityLoader.cs 31 Dec 2004 20:57:44 -0000 1.8 --- EntityLoader.cs 1 Mar 2005 16:24:48 -0000 1.9 *************** *** 19,24 **** /// </summary> /// <param name="persister"></param> /// <param name="factory"></param> ! public EntityLoader( ILoadable persister, ISessionFactoryImplementor factory ) : base( persister, factory ) { idType = new IType[ ] {persister.IdentifierType}; --- 19,37 ---- /// </summary> /// <param name="persister"></param> + /// <param name="batchSize"></param> /// <param name="factory"></param> ! public EntityLoader( ILoadable persister, int batchSize, ISessionFactoryImplementor factory ) : this( persister, persister.IdentifierColumnNames, persister.IdentifierType, batchSize, factory ) ! { ! } ! ! /// <summary> ! /// ! /// </summary> ! /// <param name="persister"></param> ! /// <param name="uniqueKey"></param> ! /// <param name="uniqueKeyType"></param> ! /// <param name="batchSize"></param> ! /// <param name="factory"></param> ! public EntityLoader( ILoadable persister, string[] uniqueKey, IType uniqueKeyType, int batchSize, ISessionFactoryImplementor factory ) : base( persister, factory ) { idType = new IType[ ] {persister.IdentifierType}; *************** *** 38,46 **** /// <param name="session"></param> /// <param name="id"></param> /// <param name="obj"></param> /// <returns></returns> public object Load( ISessionImplementor session, object id, object obj ) { ! IList list = LoadEntity( session, new object[ ] {id}, idType, obj, id, false ); if( list.Count == 1 ) { --- 51,83 ---- /// <param name="session"></param> /// <param name="id"></param> + /// <returns></returns> + public object LoadByUniqueKey( ISessionImplementor session, object id ) + { + return Load( session, id, null, null ); + } + + /// <summary> + /// + /// </summary> + /// <param name="session"></param> + /// <param name="id"></param> /// <param name="obj"></param> /// <returns></returns> public object Load( ISessionImplementor session, object id, object obj ) { ! return Load( session, id, obj, id ); ! } ! ! /// <summary> ! /// ! /// </summary> ! /// <param name="session"></param> ! /// <param name="id"></param> ! /// <param name="obj"></param> ! /// <param name="optionalId"></param> ! /// <returns></returns> ! public object Load( ISessionImplementor session, object id, object obj, object optionalId ) ! { ! IList list = LoadEntity( session, new object[ ] {id}, idType, obj, optionalId, false ); if( list.Count == 1 ) { *************** *** 53,61 **** else { ! throw new HibernateException( ! "More than one row with the given identifier was found: " + id + ", for class: " + Persister.ClassName ); } } --- 90,105 ---- else { ! if ( CollectionOwner > -1 ) ! { ! return list[ 0 ]; ! } ! else ! { ! throw new HibernateException( ! "More than one row with the given identifier was found: " + id + ", for class: " + Persister.ClassName ); + } } } |