|
From: Michael D. <mik...@us...> - 2004-04-26 03:45:18
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Type In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1793/NHibernate/Type Modified Files: ComponentType.cs PersistentCollectionType.cs Log Message: Fixes for the problem of a Component containing a Collection causing multi data readers to be open. Fixed minor java-.net port bug with getting a range from a collection. Index: PersistentCollectionType.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Type/PersistentCollectionType.cs,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** PersistentCollectionType.cs 24 Mar 2004 19:54:02 -0000 1.8 --- PersistentCollectionType.cs 26 Apr 2004 03:45:09 -0000 1.9 *************** *** 11,15 **** /// <summary> ! /// PersistentCollectionType. /// </summary> public abstract class PersistentCollectionType : AbstractType, IAssociationType { --- 11,15 ---- /// <summary> ! /// A specific PersistentCollectionType for a Role. /// </summary> public abstract class PersistentCollectionType : AbstractType, IAssociationType { *************** *** 41,48 **** --- 41,108 ---- } + /// <summary> + /// Returns a fully initialized Collection - be careful when calling this because it might + /// open another DataReader!!! + /// </summary> + /// <param name="rs"></param> + /// <param name="name"></param> + /// <param name="session"></param> + /// <param name="owner"></param> + /// <returns></returns> public override object NullSafeGet(IDataReader rs, string[] name, ISessionImplementor session, object owner) { return ResolveIdentifier( Hydrate(rs, name, session, owner), session, owner ); } + /// <summary> + /// Gets a Collection without opening a DataReader. + /// </summary> + /// <param name="rs"></param> + /// <param name="name"></param> + /// <param name="session"></param> + /// <param name="owner"></param> + /// <param name="partOfComponent"></param> + /// <returns> + /// The Collection returned from here is a lazy-load Collection regardless of what the map says. To + /// load this Collection partOfComponent must be true and then ResolveIdentifier must be called. This + /// method is only intended to be used by ComponentType to solve the problem of Getting a Collection + /// opens a second DataReader. + /// </returns> + public object NullSafeGet(IDataReader rs, string[] name, ISessionImplementor session, object owner, bool partOfComponent) + { + object id = session.GetEntityIdentifier(owner); + PersistentCollection collection = session.GetLoadingCollection(role, id); + if(collection!=null) return collection.GetCachedValue(); //TODO: yuck... call another method - H2.0.3comment + + CollectionPersister persister = session.Factory.GetCollectionPersister(role); + collection = persister.GetCachedCollection(id, owner, session); + if(collection!=null) + { + session.AddInitializedCollection(collection, persister, id); + return collection.GetCachedValue(); + } + else + { + + collection = Instantiate(session, persister); + session.AddUninitializedCollection(collection, persister, id); + + // hard coding in lazy here because we don't want it to load during it's Get - just + // initialize the Collection class as if it is being lazy loaded - we'll get back to + // loading it during ResolveIdentifier... + collection.GetInitialValue(true); + + // if we get to here then we have just created a lazy loaded (ie - uninitialized )Collection that might + // be a part of a Component. If it is part of a component then we need to mark it as + // needing to be a part of the batch that gets ResolveIdentifier called where it will be Initialized + // according to the IsLazy property of the Persister + if(partOfComponent) + { + session.AddUnresolvedComponentCollection(id, role, collection); + } + + return collection; + } + } + public virtual object GetCollection(object id, object owner, ISessionImplementor session) { PersistentCollection collection = session.GetLoadingCollection(role, id); *************** *** 156,159 **** --- 216,228 ---- } + /// <summary> + /// + /// </summary> + /// <param name="value">The id of the owner.</param> + /// <param name="session"></param> + /// <param name="owner"></param> + /// <returns></returns> + /// <remarks> + /// </remarks> public override object ResolveIdentifier(object value, ISessionImplementor session, object owner) { if (value==null) { *************** *** 165,168 **** --- 234,278 ---- } + /// <summary> + /// Resolves Collection that might be part of a Component. + /// </summary> + /// <param name="value">The id of the owner.</param> + /// <param name="session">The current Session.</param> + /// <param name="owner">The owner of the collection.</param> + /// <param name="partOfComponent">Indicates if this Collection is a part of a Component.</param> + /// <returns>A fully initialized collection according to its Persister's IsLazy property.</returns> + public object ResolveIdentifier(object value, ISessionImplementor session, object owner, bool partOfComponent) + { + if(partOfComponent==false) return ResolveIdentifier(value, session, owner); + + // check to see if this Collection is part of a Component and it has already been Instantiated + // and just needs to GetInitialValue because it has already been Instantiated and Added to the + // Session in NullSafeGet + object id = value; + + PersistentCollection collection = session.GetUnresolvedComponentCollection(id, role); + + if(collection==null) + { + // when the collection is null that means it is not an UnresolvedComponentCollection + // so we can let ResolveIdentifier get it however it needs to. + return ResolveIdentifier(id, session, owner); + } + else + { + // we already have a collection + CollectionPersister persister = session.Factory.GetCollectionPersister(role); + collection.GetInitialValue(persister.IsLazy); + + // we have resolved the Collection in the Component so remove it from the unresolved + session.RemoveUnresolvedComponentCollection(id, role); + + return collection; + } + + + + } + public virtual bool IsArrayType { get { return false; } Index: ComponentType.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Type/ComponentType.cs,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** ComponentType.cs 10 Feb 2004 18:41:42 -0000 1.6 --- ComponentType.cs 26 Apr 2004 03:45:09 -0000 1.7 *************** *** 112,116 **** } ! public override object NullSafeGet(IDataReader rs, string[] names, ISessionImplementor session, object owner) { int begin = 0; bool notNull=false; --- 112,164 ---- } ! /// <summary> ! /// Provides component specific implementation of ResolveIdentifier that is safe for Collections. ! /// </summary> ! /// <param name="value">The Component object.</param> ! /// <param name="session">The current Session.</param> ! /// <param name="owner">The Entity object the Component is contained in.</param> ! /// <returns>A fully resolved Component.</returns> ! public override object ResolveIdentifier(object value, ISessionImplementor session, object owner) ! { ! if(value==null) return null; ! ! for(int i=0; i < propertySpan; i++) ! { ! // the only types we need to resolve are PersistentCollectionTypes and ComponentTypes. ! // ComponentTypes only really need to be resolved when they contain other ComponentTypes ! // that contain Collections, I'm not sure how safe it is to call Set(target, val) during ! // ResolveIdentifier - commented out the Set because this is not creating new objects, just ! // modifying the existing ones so they don't need to be Set again. ! // Nor am I sure how safe it is to ignore ResolveIdentifer for everything ! // else. I know ManyToOneType and OneToOneType also override ResolveIdentifer and can potentially ! // connect to the db. ! ! if(types[i] is PersistentCollectionType) ! { ! object id = session.GetEntityIdentifier(owner); ! object val = ((PersistentCollectionType)types[i]).ResolveIdentifier(id, session, owner, true); ! //setters[i].Set(value, val); ! } ! else ! { ! object val = types[i].ResolveIdentifier(getters[i].Get(value), session, owner); ! //setters[i].Set(value, val); ! } ! } ! ! return value; ! ! } ! ! /// <summary> ! /// ! /// </summary> ! /// <param name="rs"></param> ! /// <param name="names"></param> ! /// <param name="session"></param> ! /// <param name="owner"></param> ! /// <returns></returns> ! public override object NullSafeGet(IDataReader rs, string[] names, ISessionImplementor session, object owner) ! { int begin = 0; bool notNull=false; *************** *** 119,123 **** int length = types[i].GetColumnSpan( session.Factory ); string[] range = ArrayHelper.Slice(names, begin, length); ! object val = types[i].NullSafeGet(rs, range, session, owner); if (val!=null) notNull=true; values[i] = val; --- 167,187 ---- int length = types[i].GetColumnSpan( session.Factory ); string[] range = ArrayHelper.Slice(names, begin, length); ! object val = null; //types[i].NullSafeGet(rs, range, session, owner); ! ! // if the Component contains a collection type then use its special NullSafeGet ! // so that we don't create another IDataReader to Get the Collections values from ! // the Db. This breaks the nice OO'ness of being able to just call type.NullSafeGet ! // but it solves the problem of Collections inside of Components opening another ! // DataReader... ! if(types[i] is PersistentCollectionType) ! { ! val = ((PersistentCollectionType)types[i]).NullSafeGet(rs, range, session, owner, true); ! } ! else ! { ! val = types[i].NullSafeGet(rs, range, session, owner); ! } ! ! if (val!=null) notNull=true; values[i] = val; |