/// <summary> /// Initializes a new instance of <see cref="CollectionEntry"/>. /// </summary> /// <param name="cs">The <see cref="ICollectionSnapshot"/> from another <see cref="ISession"/>.</param> /// <param name="factory">The <see cref="ISessionFactoryImplementor"/> that created this <see cref="ISession"/>.</param> /// <remarks> /// This takes an <see cref="ICollectionSnapshot"/> from another <see cref="ISession"/> and /// creates an entry for it in this <see cref="ISession"/> by copying the values from the /// <c>cs</c> parameter. /// </remarks> public CollectionEntry(ICollectionSnapshot cs, ISessionFactoryImplementor factory) { this.dirty = cs.Dirty; this.snapshot = cs.Snapshot; this.loadedKey = cs.Key; this.initialized = true; // Detached collections that get found and reattached during flush // shouldn't be ignored this.ignore = false; SetLoadedPersister(factory.GetCollectionPersister(cs.Role)); }
/// <summary> /// Reattach a detached (disassociated) initialized or uninitialized /// collection wrapper, using a snapshot carried with the collection wrapper /// </summary> protected internal void ReattachCollection(IPersistentCollection collection, ICollectionSnapshot snapshot) { if (collection.WasInitialized) { Session.PersistenceContext.AddInitializedDetachedCollection(collection, snapshot); } else { if (!IsCollectionSnapshotValid(snapshot)) throw new HibernateException("could not reassociate uninitialized transient collection"); Session.PersistenceContext.AddUninitializedDetachedCollection(collection, snapshot); } }
protected override object ProcessCollection(object collection, PersistentCollectionType type) { ICollectionPersister persister = Session.GetCollectionPersister(type.Role); if (collection == null) { // Do nothing } else if (collection is PersistentCollection) { PersistentCollection coll = (PersistentCollection)collection; if (coll.SetCurrentSession(Session)) { ICollectionSnapshot snapshot = coll.CollectionSnapshot; if (SessionImpl.IsOwnerUnchanged(snapshot, persister, this.Key)) { // a "detached" collection that originally belonged to the same entity if (snapshot.Dirty) { throw new HibernateException("reassociated object has dirty collection"); } Session.ReattachCollection(coll, snapshot); } else { // a "detached" collection that belonged to a different entity throw new HibernateException("reassociated object has dirty collection reference"); } } else { // a collection loaded in the current session // can not possibly be the collection belonging // to the entity passed to update() throw new HibernateException("reassociated object has dirty collection reference"); } } else { // brand new collection //TODO: or an array!! we can't lock objects with arrays now?? throw new HibernateException("reassociated object has dirty collection reference"); } return(null); }
protected override object ProcessCollection(object collection, PersistentCollectionType type) { ICollectionPersister persister = Session.GetCollectionPersister(type.Role); if (collection is PersistentCollection) { PersistentCollection wrapper = (PersistentCollection)collection; if (wrapper.SetCurrentSession(Session)) { //a "detached" collection! ICollectionSnapshot snapshot = wrapper.CollectionSnapshot; if (!SessionImpl.IsOwnerUnchanged(snapshot, persister, Key)) { // if the collection belonged to a different entity, // clean up the existing state of the collection Session.RemoveCollection(persister, Key); } Session.ReattachCollection(wrapper, snapshot); } else { // a collection loaded in the current session // can not possibly be the collection belonging // to the entity passed to update() Session.RemoveCollection(persister, Key); } } else { // null or brand new collection // this will also (inefficiently) handle arrays, which have // no snapshot, so we can't do any better Session.RemoveCollection(persister, Key); //processArrayOrNewCollection(collection, type); } return(null); }
private static bool IsCollectionSnapshotValid(ICollectionSnapshot snapshot) { return snapshot != null && snapshot.Role != null && snapshot.Key != null; }
/// <summary> /// Has the owner of the collection changed since the collection was snapshotted and detached? /// </summary> protected internal static bool IsOwnerUnchanged(ICollectionSnapshot snapshot, ICollectionPersister persister, object id) { return IsCollectionSnapshotValid(snapshot) && persister.Role.Equals(snapshot.Role) && id.Equals(snapshot.Key); }
/// <summary> /// Initializes a new instance of <see cref="CollectionEntry"/>. /// </summary> /// <param name="cs">The <see cref="ICollectionSnapshot"/> from another <see cref="ISession"/>.</param> /// <param name="factory">The <see cref="ISessionFactoryImplementor"/> that created this <see cref="ISession"/>.</param> /// <remarks> /// This takes an <see cref="ICollectionSnapshot"/> from another <see cref="ISession"/> and /// creates an entry for it in this <see cref="ISession"/> by copying the values from the /// <c>cs</c> parameter. /// </remarks> public CollectionEntry( ICollectionSnapshot cs, ISessionFactoryImplementor factory ) { this.dirty = cs.Dirty; this.snapshot = cs.Snapshot; this.loadedKey = cs.Key; this.initialized = true; // Detached collections that get found and reattached during flush // shouldn't be ignored this.ignore = false; SetLoadedPersister( factory.GetCollectionPersister( cs.Role ) ); }
/// <summary> add a detached uninitialized collection</summary> public void AddUninitializedDetachedCollection(IPersistentCollection collection, ICollectionSnapshot snapshot) { CollectionEntry ce = new CollectionEntry(snapshot, Session.Factory); collection.CollectionSnapshot = ce; // NH Different behavior AddCollection(collection, ce, ce.Key); }
/// <summary> /// add an (initialized) collection that was created by another session and passed /// into update() (ie. one with a snapshot and existing state on the database) /// </summary> public void AddInitializedDetachedCollection(IPersistentCollection collection, ICollectionSnapshot snapshot) { if (snapshot.WasDereferenced) { //treat it just like a new collection AddCollection(collection); } else { CollectionEntry ce = new CollectionEntry(snapshot, session.Factory); collection.CollectionSnapshot = ce; // NH Different behavior AddCollection(collection, ce, ce.Key); } }
/// <summary> /// Add an (initialized) collection that was created by another session and passed /// into update() (i.e. one with a snapshot and existing state on the database) /// </summary> /// <param name="collection"></param> /// <param name="cs"></param> private void AddInitializedDetachedCollection( PersistentCollection collection, ICollectionSnapshot cs ) { if( cs.WasDereferenced ) { AddCollection( collection ); } else { CollectionEntry ce = new CollectionEntry( cs, factory ); collection.CollectionSnapshot = ce; AddCollection( collection, ce, cs.Key ); } }
/// <summary> /// Reattach a detached (disassociated) initialized or uninitialized collection wrapper /// </summary> /// <param name="collection"></param> /// <param name="snapshot"></param> internal void ReattachCollection( PersistentCollection collection, ICollectionSnapshot snapshot ) { if( collection.WasInitialized ) { AddInitializedDetachedCollection( collection, snapshot ); } else { if( !IsCollectionSnapshotValid( snapshot ) ) { throw new HibernateException( "could not reassociate uninitialized transient collection" ); } AddUninitializedDetachedCollection( collection, GetCollectionPersister( snapshot.Role ), snapshot.Key ); } }