public EntityIdentityInsertAction(object[] state, object instance, IEntityPersister persister, ISessionImplementor session, bool isDelayed)
			: base(session, null, instance, persister)
		{
			this.state = state;
			this.isDelayed = isDelayed;
			delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : null;
		}
Beispiel #2
0
 /// <summary>
 /// If an EntityKey represents a batch loadable entity, add
 /// it to the queue.
 /// </summary>
 /// <remarks>
 /// Note that the contract here is such that any key passed in should
 /// previously have been been checked for existence within the
 /// <see cref="ISession" />; failure to do so may cause the
 /// referenced entity to be included in a batch even though it is
 /// already associated with the <see cref="ISession" />.
 /// </remarks>
 public void AddBatchLoadableEntityKey(EntityKey key)
 {
     if (key.IsBatchLoadable)
     {
         batchLoadableEntityKeys[key] = Marker;
     }
 }
		/// <summary> 
		/// Associates a given entity (either transient or associated with another session) to the given session. 
		/// </summary>
		/// <param name="event">The event triggering the re-association </param>
		/// <param name="entity">The entity to be associated </param>
		/// <param name="id">The id of the entity. </param>
		/// <param name="persister">The entity's persister instance. </param>
		/// <returns> An EntityEntry representing the entity within this session. </returns>
		protected EntityEntry Reassociate(AbstractEvent @event, object entity, object id, IEntityPersister persister)
		{
			if (log.IsDebugEnabled)
			{
				log.Debug("Reassociating transient instance: " + 
					MessageHelper.InfoString(persister, id, @event.Session.Factory));
			}

			IEventSource source = @event.Session;
			EntityKey key = new EntityKey(id, persister, source.EntityMode);

			source.PersistenceContext.CheckUniqueness(key, entity);

			//get a snapshot
			object[] values = persister.GetPropertyValues(entity, source.EntityMode);
			TypeFactory.DeepCopy(values, persister.PropertyTypes, persister.PropertyUpdateability, values, source);
			object version = Versioning.GetVersion(values, persister);

			EntityEntry newEntry = source.PersistenceContext.AddEntity(entity, Status.Loaded, values, key, version, LockMode.None, true, persister, false, true);

			new OnLockVisitor(source, id, entity).Process(entity, persister);

			persister.AfterReassociate(entity, source);

			return newEntry;
		}
		private static void ProcessDereferencedCollection(IPersistentCollection coll, ISessionImplementor session)
		{
			IPersistenceContext persistenceContext = session.PersistenceContext;
			CollectionEntry entry = persistenceContext.GetCollectionEntry(coll);
			ICollectionPersister loadedPersister = entry.LoadedPersister;

			if (log.IsDebugEnabled && loadedPersister != null)
				log.Debug("Collection dereferenced: " + MessageHelper.InfoString(loadedPersister, entry.LoadedKey, session.Factory));

			// do a check
			bool hasOrphanDelete = loadedPersister != null && loadedPersister.HasOrphanDelete;
			if (hasOrphanDelete)
			{
				object ownerId = loadedPersister.OwnerEntityPersister.GetIdentifier(coll.Owner, session.EntityMode);
				// TODO NH Different behavior
				//if (ownerId == null)
				//{
				//  // the owning entity may have been deleted and its identifier unset due to
				//  // identifier-rollback; in which case, try to look up its identifier from
				//  // the persistence context
				//  if (session.Factory.Settings.IsIdentifierRollbackEnabled)
				//  {
				//    EntityEntry ownerEntry = persistenceContext.GetEntry(coll.Owner);
				//    if (ownerEntry != null)
				//    {
				//      ownerId = ownerEntry.Id;
				//    }
				//  }
				//  if (ownerId == null)
				//  {
				//    throw new AssertionFailure("Unable to determine collection owner identifier for orphan-delete processing");
				//  }
				//}
				EntityKey key = new EntityKey(ownerId, loadedPersister.OwnerEntityPersister, session.EntityMode);
				object owner = persistenceContext.GetEntity(key);
				if (owner == null)
				{
					throw new AssertionFailure("collection owner not associated with session: " + loadedPersister.Role);
				}
				EntityEntry e = persistenceContext.GetEntry(owner);
				//only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
				if (e != null && e.Status != Status.Deleted && e.Status != Status.Gone)
				{
					throw new HibernateException("A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " + loadedPersister.Role);
				}
			}

			// do the work
			entry.CurrentPersister = null;
			entry.CurrentKey = null;
			PrepareCollectionForUpdate(coll, entry, session.EntityMode, session.Factory);
		}
        protected virtual void DoEvict(object obj, EntityKey key, IEntityPersister persister, IEventSource session)
        {
            if (log.IsDebugEnabled)
            {
                log.Debug("evicting " + MessageHelper.InfoString(persister));
            }

            // remove all collections for the entity from the session-level cache
            if (persister.HasCollections)
            {
                new EvictVisitor(session).Process(obj, persister);
            }

            new Cascade(CascadingAction.Evict, CascadePoint.AfterEvict, session).CascadeOn(persister, obj);
        }
		public override bool IsNull(object owner, ISessionImplementor session)
		{
			if (propertyName != null)
			{
				IEntityPersister ownerPersister = session.Factory.GetEntityPersister(entityName);
				object id = session.GetContextEntityIdentifier(owner);

				EntityKey entityKey = new EntityKey(id, ownerPersister, session.EntityMode);

				return session.PersistenceContext.IsPropertyNull(entityKey, PropertyName);
			}
			else
			{
				return false;
			}
		}
		public virtual void OnEvict(EvictEvent @event)
		{
			IEventSource source = @event.Session;
			object obj = @event.Entity;
			IPersistenceContext persistenceContext = source.PersistenceContext;

			if (obj is INHibernateProxy)
			{
				ILazyInitializer li = ((INHibernateProxy)obj).HibernateLazyInitializer;
				object id = li.Identifier;
				IEntityPersister persister = source.Factory.GetEntityPersister(li.EntityName);
				if (id == null)
				{
					throw new ArgumentException("null identifier");
				}
				EntityKey key = new EntityKey(id, persister, source.EntityMode);
				persistenceContext.RemoveProxy(key);
				if (!li.IsUninitialized)
				{
					object entity = persistenceContext.RemoveEntity(key);
					if (entity != null)
					{
						EntityEntry e = @event.Session.PersistenceContext.RemoveEntry(entity);
						DoEvict(entity, key, e.Persister, @event.Session);
					}
				}
				li.Session = null;
			}
			else
			{
				EntityEntry e = persistenceContext.RemoveEntry(obj);
				if (e != null)
				{
					EntityKey key = new EntityKey(e.Id, e.Persister, source.EntityMode);
					persistenceContext.RemoveEntity(key);
					DoEvict(obj, key, e.Persister, source);
				}
			}
		}
		/// <summary> Adds an entity to the internal caches.</summary>
		public EntityEntry AddEntity(object entity, Status status, object[] loadedState, EntityKey entityKey, object version,
																 LockMode lockMode, bool existsInDatabase, IEntityPersister persister,
																 bool disableVersionIncrement, bool lazyPropertiesAreUnfetched)
		{
			AddEntity(entityKey, entity);

			return AddEntry(entity, status, loadedState, null, entityKey.Identifier, version, lockMode, existsInDatabase, persister, disableVersionIncrement, lazyPropertiesAreUnfetched);
		}
		/// <summary> 
		/// Associate a proxy that was instantiated by another session with this session
		/// </summary>
		/// <param name="li">The proxy initializer. </param>
		/// <param name="proxy">The proxy to reassociate. </param>
		private void ReassociateProxy(ILazyInitializer li, INHibernateProxy proxy)
		{
			if (li.Session != Session)
			{
				IEntityPersister persister = session.Factory.GetEntityPersister(li.EntityName);
				EntityKey key = new EntityKey(li.Identifier, persister, session.EntityMode);
				// any earlier proxy takes precedence
				if (!proxiesByKey.ContainsKey(key))
				{
					proxiesByKey[key] = proxy;
				}
				proxy.HibernateLazyInitializer.Session = Session;
			}
		}
Beispiel #10
0
		/// <summary>
		/// Hydrate the state of an object from the SQL <c>IDataReader</c>, into
		/// an array of "hydrated" values (do not resolve associations yet),
		/// and pass the hydrated state to the session.
		/// </summary>
		private void LoadFromResultSet(IDataReader rs, int i, object obj, string instanceClass, EntityKey key,
		                               string rowIdAlias, LockMode lockMode, ILoadable rootPersister,
		                               ISessionImplementor session)
		{
			object id = key.Identifier;

			// Get the persister for the _subclass_
			ILoadable persister = (ILoadable) Factory.GetEntityPersister(instanceClass);

			if (log.IsDebugEnabled)
			{
				log.Debug("Initializing object from DataReader: " + MessageHelper.InfoString(persister, id));
			}

			bool eagerPropertyFetch = IsEagerPropertyFetchEnabled(i);

			// add temp entry so that the next step is circular-reference
			// safe - only needed because some types don't take proper
			// advantage of two-phase-load (esp. components)
			TwoPhaseLoad.AddUninitializedEntity(key, obj, persister, lockMode, !eagerPropertyFetch, session);

			// This is not very nice (and quite slow):
			string[][] cols = persister == rootPersister
			                  	? EntityAliases[i].SuffixedPropertyAliases
			                  	: EntityAliases[i].GetSuffixedPropertyAliases(persister);

			object[] values = persister.Hydrate(rs, id, obj, rootPersister, cols, eagerPropertyFetch, session);

			object rowId = persister.HasRowId ? rs[rowIdAlias] : null;

			IAssociationType[] ownerAssociationTypes = OwnerAssociationTypes;
			if (ownerAssociationTypes != null && ownerAssociationTypes[i] != null)
			{
				string ukName = ownerAssociationTypes[i].RHSUniqueKeyPropertyName;
				if (ukName != null)
				{
					int index = ((IUniqueKeyLoadable) persister).GetPropertyIndex(ukName);
					IType type = persister.PropertyTypes[index];

					// polymorphism not really handled completely correctly,
					// perhaps...well, actually its ok, assuming that the
					// entity name used in the lookup is the same as the
					// the one used here, which it will be

					EntityUniqueKey euk =
						new EntityUniqueKey(rootPersister.EntityName, ukName, type.SemiResolve(values[index], session, obj), type,
						                    session.EntityMode, session.Factory);
					session.PersistenceContext.AddEntity(euk, obj);
				}
			}

			TwoPhaseLoad.PostHydrate(persister, id, values, rowId, obj, lockMode, !eagerPropertyFetch, session);
		}
Beispiel #11
0
 public AssociationKey(EntityKey ownerKey, string propertyName)
 {
     this.ownerKey     = ownerKey;
     this.propertyName = propertyName;
 }
Beispiel #12
0
		/// <summary>
		/// For missing objects associated by one-to-one with another object in the
		/// result set, register the fact that the the object is missing with the
		/// session.
		/// </summary>
		private void RegisterNonExists(EntityKey[] keys, ISessionImplementor session)
		{
			int[] owners = Owners;
			if (owners != null)
			{
				EntityType[] ownerAssociationTypes = OwnerAssociationTypes;
				for (int i = 0; i < keys.Length; i++)
				{
					int owner = owners[i];
					if (owner > -1)
					{
						EntityKey ownerKey = keys[owner];
						if (keys[i] == null && ownerKey != null)
						{
							bool isOneToOneAssociation = ownerAssociationTypes != null && ownerAssociationTypes[i] != null
							                             && ownerAssociationTypes[i].IsOneToOne;
							if (isOneToOneAssociation)
							{
								session.PersistenceContext.AddNullProperty(ownerKey, ownerAssociationTypes[i].PropertyName);
							}
						}
					}
				}
			}
		}
Beispiel #13
0
		/// <summary>
		/// The entity instance is already in the session cache
		/// </summary>
		private void InstanceAlreadyLoaded(IDataReader rs, int i, IEntityPersister persister, EntityKey key, object obj,
		                                   LockMode lockMode, ISessionImplementor session)
		{
			if (!persister.IsInstance(obj, session.EntityMode))
			{
				string errorMsg = string.Format("loading object was of wrong class [{0}]", obj.GetType().FullName);
				throw new WrongClassException(errorMsg, key.Identifier, persister.EntityName);
			}

			if (LockMode.None != lockMode && UpgradeLocks())
			{
				EntityEntry entry = session.PersistenceContext.GetEntry(obj);
				bool isVersionCheckNeeded = persister.IsVersioned && entry.LockMode.LessThan(lockMode);

				// we don't need to worry about existing version being uninitialized
				// because this block isn't called by a re-entrant load (re-entrant
				// load _always_ have lock mode NONE
				if (isVersionCheckNeeded)
				{
					// we only check the version when _upgrading_ lock modes
					CheckVersion(i, persister, key.Identifier, obj, rs, session);
					// we need to upgrade the lock mode to the mode requested
					entry.LockMode = lockMode;
				}
			}
		}
		/// <summary> 
		/// Performs all the actual work needed to save an entity (well to get the save moved to
		/// the execution queue). 
		/// </summary>
		/// <param name="entity">The entity to be saved </param>
		/// <param name="key">The id to be used for saving the entity (or null, in the case of identity columns) </param>
		/// <param name="persister">The entity's persister instance. </param>
		/// <param name="useIdentityColumn">Should an identity column be used for id generation? </param>
		/// <param name="anything">Generally cascade-specific information. </param>
		/// <param name="source">The session which is the source of the current event. </param>
		/// <param name="requiresImmediateIdAccess">
		/// Is access to the identifier required immediately
		/// after the completion of the save?  persist(), for example, does not require this... 
		/// </param>
		/// <returns> 
		/// The id used to save the entity; may be null depending on the
		/// type of id generator used and the requiresImmediateIdAccess value
		/// </returns>
		protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IEntityPersister persister, bool useIdentityColumn, object anything, IEventSource source, bool requiresImmediateIdAccess)
		{
			Validate(entity, persister, source);

			object id = key == null ? null : key.Identifier;

			// NH Different behavior (shouldDelayIdentityInserts=false anyway)
			//bool inTxn = source.ConnectionManager.IsInActiveTransaction;
			//bool shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
			bool shouldDelayIdentityInserts = false;

			// Put a placeholder in entries, so we don't recurse back and try to save() the
			// same object again. QUESTION: should this be done before onSave() is called?
			// likewise, should it be done before onUpdate()?
			source.PersistenceContext.AddEntry(entity, Status.Saving, null, null, id, null, LockMode.Write, useIdentityColumn, persister, false, false);

			CascadeBeforeSave(source, persister, entity, anything);

			// NH-962: This was originally done before many-to-one cascades.
			if (useIdentityColumn && !shouldDelayIdentityInserts)
			{
				log.Debug("executing insertions");
				source.ActionQueue.ExecuteInserts();
			}

			object[] values = persister.GetPropertyValuesToInsert(entity, GetMergeMap(anything), source);
			IType[] types = persister.PropertyTypes;

			bool substitute = SubstituteValuesIfNecessary(entity, id, values, persister, source);

			if (persister.HasCollections)
			{
				substitute = substitute || VisitCollectionsBeforeSave(entity, id, values, types, source);
			}

			if (substitute)
			{
				persister.SetPropertyValues(entity, values, source.EntityMode);
			}

			TypeHelper.DeepCopy(values, types, persister.PropertyUpdateability, values, source);

			new ForeignKeys.Nullifier(entity, false, useIdentityColumn, source).NullifyTransientReferences(values, types);
			new Nullability(source).CheckNullability(values, persister, false);

			if (useIdentityColumn)
			{
				EntityIdentityInsertAction insert = new EntityIdentityInsertAction(values, entity, persister, source, shouldDelayIdentityInserts);
				if (!shouldDelayIdentityInserts)
				{
					log.Debug("executing identity-insert immediately");
					source.ActionQueue.Execute(insert);
					id = insert.GeneratedId;
					//now done in EntityIdentityInsertAction
					//persister.setIdentifier( entity, id, source.getEntityMode() );
					key = source.GenerateEntityKey(id, persister);
					source.PersistenceContext.CheckUniqueness(key, entity);
					//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
				}
				else
				{
					log.Debug("delaying identity-insert due to no transaction in progress");
					source.ActionQueue.AddAction(insert);
					key = insert.DelayedEntityKey;
				}
			}

			object version = Versioning.GetVersion(values, persister);
			source.PersistenceContext.AddEntity(
				entity, 
				persister.IsMutable ? Status.Loaded : Status.ReadOnly,
				values, key, 
				version, 
				LockMode.Write, 
				useIdentityColumn, 
				persister, 
				VersionIncrementDisabled, 
				false);
			//source.getPersistenceContext().removeNonExist( new EntityKey( id, persister, source.getEntityMode() ) );

			if (!useIdentityColumn)
			{
				source.ActionQueue.AddAction(new EntityInsertAction(id, values, entity, version, persister, source));
			}

			CascadeAfterSave(source, persister, entity, anything);

			MarkInterceptorDirty(entity, persister, source);

			return id;
		}
 /// <summary>
 /// Checks whether the entity key was already checked in the cache.
 /// </summary>
 /// <param name="persister">The entity persister.</param>
 /// <param name="key">The entity key.</param>
 /// <returns><see langword="true"/> whether the entity key was checked, <see langword="false"/> otherwise.</returns>
 internal bool WasEntityKeyChecked(IEntityPersister persister, EntityKey key)
 {
     return(_queryCheckedEntityKeys.TryGetValue(persister.EntityName, out var checkedKeys) &&
            checkedKeys.Contains(key));
 }
		/// <summary> 
		/// Attempts to check whether the given key represents an entity already loaded within the
		/// current session.
		/// </summary>
		/// <param name="obj">The entity reference against which to perform the uniqueness check.</param>
		/// <param name="key">The entity key.</param>
		public void CheckUniqueness(EntityKey key, object obj)
		{
			object entity = GetEntity(key);
			if (entity == obj)
			{
				throw new AssertionFailure("object already associated, but no entry was found");
			}
			if (entity != null)
			{
				throw new NonUniqueObjectException(key.Identifier, key.EntityName);
			}
		}
		/// <summary> 
		/// Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
		/// third argument (the entity associated with the key) if no proxy exists. Init
		/// the proxy to the target implementation, if necessary.
		/// </summary>
		public object ProxyFor(IEntityPersister persister, EntityKey key, object impl)
		{
			if (!persister.HasProxy || key == null)
				return impl;

			INHibernateProxy proxy;
			if (proxiesByKey.TryGetValue(key, out proxy))
			{
				return NarrowProxy(proxy, persister, key, impl);
			}
			else
			{
				return impl;
			}
		}
 /// <summary>
 /// Add an uninitialized instance of an entity class, as a placeholder to ensure object
 /// identity. Must be called before <tt>postHydrate()</tt>.
 /// Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
 /// but we need the mapping from id to instance in order to guarantee uniqueness.
 /// </summary>
 public static void AddUninitializedEntity(EntityKey key, object obj, IEntityPersister persister, LockMode lockMode, ISessionImplementor session)
 {
     session.PersistenceContext.AddEntity(obj, Status.Loading, null, key, null, lockMode, true, persister, false);
 }
 /// <summary>
 /// Adds a subselect fetch decriptor for the given entity key.
 /// </summary>
 /// <param name="key">The entity for which to register the subselect fetch.</param>
 /// <param name="subquery">The fetch descriptor.</param>
 public void AddSubselect(EntityKey key, SubselectFetch subquery)
 {
     subselectsByEntityKey[key] = subquery;
 }
 /// <summary>
 /// After evicting or deleting an entity, we don't need to
 /// know the query that was used to load it anymore (don't
 /// call this after loading the entity, since we might still
 /// need to load its collections)
 /// </summary>
 public void RemoveSubselect(EntityKey key)
 {
     subselectsByEntityKey.Remove(key);
 }
Beispiel #21
0
        private static Task ProcessDereferencedCollectionAsync(IPersistentCollection coll, ISessionImplementor session, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            try
            {
                IPersistenceContext  persistenceContext = session.PersistenceContext;
                CollectionEntry      entry           = persistenceContext.GetCollectionEntry(coll);
                ICollectionPersister loadedPersister = entry.LoadedPersister;

                if (log.IsDebugEnabled && loadedPersister != null)
                {
                    log.Debug("Collection dereferenced: " + MessageHelper.CollectionInfoString(loadedPersister, coll, entry.LoadedKey, session));
                }

                // do a check
                bool hasOrphanDelete = loadedPersister != null && loadedPersister.HasOrphanDelete;
                if (hasOrphanDelete)
                {
                    object ownerId = loadedPersister.OwnerEntityPersister.GetIdentifier(coll.Owner);
                    // TODO NH Different behavior
                    //if (ownerId == null)
                    //{
                    //  // the owning entity may have been deleted and its identifier unset due to
                    //  // identifier-rollback; in which case, try to look up its identifier from
                    //  // the persistence context
                    //  if (session.Factory.Settings.IsIdentifierRollbackEnabled)
                    //  {
                    //    EntityEntry ownerEntry = persistenceContext.GetEntry(coll.Owner);
                    //    if (ownerEntry != null)
                    //    {
                    //      ownerId = ownerEntry.Id;
                    //    }
                    //  }
                    //  if (ownerId == null)
                    //  {
                    //    throw new AssertionFailure("Unable to determine collection owner identifier for orphan-delete processing");
                    //  }
                    //}
                    EntityKey key   = session.GenerateEntityKey(ownerId, loadedPersister.OwnerEntityPersister);
                    object    owner = persistenceContext.GetEntity(key);
                    if (owner == null)
                    {
                        return(Task.FromException <object>(new AssertionFailure("collection owner not associated with session: " + loadedPersister.Role)));
                    }
                    EntityEntry e = persistenceContext.GetEntry(owner);
                    //only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
                    if (e != null && e.Status != Status.Deleted && e.Status != Status.Gone)
                    {
                        return(Task.FromException <object>(new HibernateException("A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " + loadedPersister.Role)));
                    }
                }

                // do the work
                entry.CurrentPersister = null;
                entry.CurrentKey       = null;
                return(PrepareCollectionForUpdateAsync(coll, entry, session.Factory, cancellationToken));
            }
            catch (System.Exception ex)
            {
                return(Task.FromException <object>(ex));
            }
        }
Beispiel #22
0
 public static void AddUninitializedCachedEntity(EntityKey key, object obj, IEntityPersister persister, LockMode lockMode, bool lazyPropertiesAreUnfetched, object version, ISessionImplementor session)
 {
     session.PersistenceContext.AddEntity(obj, Status.Loading, null, key, version, lockMode, true, persister, false, lazyPropertiesAreUnfetched);
 }
		/// <summary> 
		/// If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy
		/// and overwrite the registration of the old one. This breaks == and occurs only for
		/// "class" proxies rather than "interface" proxies. Also init the proxy to point to
		/// the given target implementation if necessary. 
		/// </summary>
		/// <param name="proxy">The proxy instance to be narrowed. </param>
		/// <param name="persister">The persister for the proxied entity. </param>
		/// <param name="key">The internal cache key for the proxied entity. </param>
		/// <param name="obj">(optional) the actual proxied entity instance. </param>
		/// <returns> An appropriately narrowed instance. </returns>
		public object NarrowProxy(INHibernateProxy proxy, IEntityPersister persister, EntityKey key, object obj)
		{
			bool alreadyNarrow = persister.GetConcreteProxyClass(session.EntityMode).IsAssignableFrom(proxy.GetType());

			if (!alreadyNarrow)
			{
				if (ProxyWarnLog.IsWarnEnabled)
				{
					ProxyWarnLog.Warn("Narrowing proxy to " + persister.GetConcreteProxyClass(session.EntityMode) + " - this operation breaks ==");
				}

				if (obj != null)
				{
					proxiesByKey.Remove(key);
					return obj; //return the proxied object
				}
				else
				{
					proxy = (INHibernateProxy)persister.CreateProxy(key.Identifier, session);
					proxiesByKey[key] = proxy; //overwrite old proxy
					return proxy;
				}
			}
			else
			{
				if (obj != null)
				{
					proxy.HibernateLazyInitializer.SetImplementation(obj);
				}
				return proxy;
			}
		}
		/// <summary>
		/// Return the Underlying Persistent Object in a given <see cref="ISession"/>, or null.
		/// </summary>
		/// <param name="s">The Session to get the object from.</param>
		/// <returns>The Persistent Object this proxy is Proxying, or <see langword="null" />.</returns>
		public object GetImplementation(ISessionImplementor s)
		{
			EntityKey key = new EntityKey(Identifier, s.Factory.GetEntityPersister(PersistentClass));
			return s.GetEntity(key);
		}
		public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready)
		{
			IEventSource source = @event.Session;

			if (source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity))
				return;

			object obj = source.PersistenceContext.UnproxyAndReassociate(@event.Entity);

			if (refreshedAlready.Contains(obj))
			{
				log.Debug("already refreshed");
				return;
			}

			EntityEntry e = source.PersistenceContext.GetEntry(obj);
			IEntityPersister persister;
			object id;

			if (e == null)
			{
				persister = source.GetEntityPersister(null, obj); //refresh() does not pass an entityName
				id = persister.GetIdentifier(obj, source.EntityMode);
				if (log.IsDebugEnabled)
				{
					log.Debug("refreshing transient " + MessageHelper.InfoString(persister, id, source.Factory));
				}
				EntityKey key = new EntityKey(id, persister, source.EntityMode);
				if (source.PersistenceContext.GetEntry(key) != null)
				{
					throw new PersistentObjectException("attempted to refresh transient instance when persistent instance was already associated with the Session: " + 
						MessageHelper.InfoString(persister, id, source.Factory));
				}
			}
			else
			{
				if (log.IsDebugEnabled)
				{
					log.Debug("refreshing " + MessageHelper.InfoString(e.Persister, e.Id, source.Factory));
				}
				if (!e.ExistsInDatabase)
				{
					throw new HibernateException("this instance does not yet exist as a row in the database");
				}

				persister = e.Persister;
				id = e.Id;
			}

			// cascade the refresh prior to refreshing this entity
			refreshedAlready[obj] = obj;
			new Cascade(CascadingAction.Refresh, CascadePoint.BeforeRefresh, source).CascadeOn(persister, obj, refreshedAlready);

			if (e != null)
			{
				EntityKey key = new EntityKey(id, persister, source.EntityMode);
				source.PersistenceContext.RemoveEntity(key);
				if (persister.HasCollections)
					new EvictVisitor(source).Process(obj, persister);
			}

			if (persister.HasCache)
			{
				CacheKey ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, source.EntityMode, source.Factory);
				persister.Cache.Remove(ck);
			}

			EvictCachedCollections(persister, id, source.Factory);

			// NH Different behavior : NH-1601
			// At this point the entity need the real refresh, all elementes of collections are Refreshed,
			// the collection state was evicted, but the PersistentCollection (in the entity state)
			// is associated with a possible previous session.
			new WrapVisitor(source).Process(obj, persister);

			string previousFetchProfile = source.FetchProfile;
			source.FetchProfile = "refresh";
			object result = persister.Load(id, obj, @event.LockMode, source);
			source.FetchProfile = previousFetchProfile;
			// NH Different behavior : we are ignoring transient entities without throw any kind of exception 
			// because a transient entity is "self refreshed"
			if (!ForeignKeys.IsTransient(persister.EntityName, obj, result == null, @event.Session))
				UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName);
		}
Beispiel #26
0
		internal object GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session,
		                                    QueryParameters queryParameters, LockMode[] lockModeArray,
		                                    EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys,
		                                    bool returnProxies)
		{
			ILoadable[] persisters = EntityPersisters;
			int entitySpan = persisters.Length;

			for (int i = 0; i < entitySpan; i++)
			{
				keys[i] =
					GetKeyFromResultSet(i, persisters[i], i == entitySpan - 1 ? queryParameters.OptionalId : null, resultSet, session);
				//TODO: the i==entitySpan-1 bit depends upon subclass implementation (very bad)
			}

			RegisterNonExists(keys, session);

			// this call is side-effecty
			object[] row =
				GetRow(resultSet, persisters, keys, queryParameters.OptionalObject, optionalObjectKey, lockModeArray,
				       hydratedObjects, session);

			ReadCollectionElements(row, resultSet, session);

			if (returnProxies)
			{
				// now get an existing proxy for each row element (if there is one)
				for (int i = 0; i < entitySpan; i++)
				{
					object entity = row[i];
					object proxy = session.PersistenceContext.ProxyFor(persisters[i], keys[i], entity);

					if (entity != proxy)
					{
						// Force the proxy to resolve itself
						((INHibernateProxy) proxy).HibernateLazyInitializer.SetImplementation(entity);
						row[i] = proxy;
					}
				}
			}

			return GetResultColumnOrRow(row, queryParameters.ResultTransformer, resultSet, session);
		}
		/// <summary>
		/// Invokes the method if this is something that the LazyInitializer can handle
		/// without the underlying proxied object being instantiated.
		/// </summary>
		/// <param name="method">The name of the method/property to Invoke.</param>
		/// <param name="args">The arguments to pass the method/property.</param>
		/// <param name="proxy">The proxy object that the method is being invoked on.</param>
		/// <returns>
		/// The result of the Invoke if the underlying proxied object is not needed.  If the 
		/// underlying proxied object is needed then it returns the result <see cref="InvokeImplementation"/>
		/// which indicates that the Proxy will need to forward to the real implementation.
		/// </returns>
		public virtual object Invoke(MethodBase method, object[] args, object proxy)
		{
			string methodName = method.Name;
			int paramCount = method.GetParameters().Length;

			if (paramCount == 0)
			{
				if (!_overridesEquals && methodName == "GetHashCode")
				{
					return IdentityHashCodeProvider.GetHashCode(proxy);
				}
				else if (method.Equals(_getIdentifierMethod))
				{
					return _id;
				}
				else if (methodName == "Finalize")
				{
					return null;
				}
			}
			else if (paramCount == 1)
			{
				if (!_overridesEquals && methodName == "Equals")
				{
					return args[0] == proxy;
				}
				else if (method.Equals(_setIdentifierMethod))
				{
					Initialize();
					_id = args[0];
					return InvokeImplementation;
				}
			}
			else if (paramCount == 2)
			{
				// if the Proxy Engine delegates the call of GetObjectData to the Initializer
				// then we need to handle it.  Castle.DynamicProxy takes care of serializing
				// proxies for us, but other providers might not.
				if (methodName == "GetObjectData")
				{
					SerializationInfo info = (SerializationInfo) args[0];
					StreamingContext context = (StreamingContext) args[1]; // not used !?!

					if (_target == null & _session != null)
					{
						EntityKey key = new EntityKey(_id, _session.Factory.GetEntityPersister(_persistentClass));
						_target = _session.GetEntity(key);
					}

					// let the specific LazyInitializer write its requirements for deserialization 
					// into the stream.
					AddSerializationInfo(info, context);

					// don't need a return value for proxy.
					return null;
				}
			}

			return InvokeImplementation;
		}
Beispiel #28
0
		/// <summary>
		/// Retrieve the fetch descriptor associated with the given entity key.
		/// </summary>
		/// <param name="key">The entity key for which to locate any defined subselect fetch.</param>
		/// <returns>The fetch descriptor; may return null if no subselect fetch queued for
		/// this entity key.</returns>
		public SubselectFetch GetSubselect(EntityKey key)
		{
			SubselectFetch result;
			subselectsByEntityKey.TryGetValue(key, out result);
			return result;
		}
        public void Delete(object id, object version, object obj, ISessionImplementor session)
        {
            int span = TableSpan;
            bool isImpliedOptimisticLocking = !entityMetamodel.IsVersioned &&
                                                                                entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version;
            object[] loadedState = null;
            if (isImpliedOptimisticLocking)
            {
                // need to treat this as if it where optimistic-lock="all" (dirty does *not* make sense);
                // first we need to locate the "loaded" state
                //
                // Note, it potentially could be a proxy, so perform the location the safe way...
                EntityKey key = new EntityKey(id, this, session.EntityMode);
                object entity = session.PersistenceContext.GetEntity(key);
                if (entity != null)
                {
                    EntityEntry entry = session.PersistenceContext.GetEntry(entity);
                    loadedState = entry.LoadedState;
                }
            }

            SqlCommandInfo[] deleteStrings;
            if (isImpliedOptimisticLocking && loadedState != null)
            {
                // we need to utilize dynamic delete statements
                deleteStrings = GenerateSQLDeleteStrings(loadedState);
            }
            else
            {
                // otherwise, utilize the static delete statements
                deleteStrings = SqlDeleteStrings;
            }

            for (int j = span - 1; j >= 0; j--)
            {
                Delete(id, version, j, obj, deleteStrings[j], session, loadedState);
            }
        }
		/// <summary> 
		/// Retrieve the cached database snapshot for the requested entity key.
		/// </summary>
		/// <param name="key">The entity key for which to retrieve the cached snapshot </param>
		/// <returns> The cached snapshot </returns>
		/// <remarks>
		/// <list type="bullet">
		/// <listheader><description>This differs from <see cref="GetDatabaseSnapshot"/> is two important respects:</description></listheader>
		/// <item><description>no snapshot is obtained from the database if not already cached</description></item>
		/// <item><description>an entry of NO_ROW here is interpreted as an exception</description></item>
		/// </list>
		/// </remarks>
		public object[] GetCachedDatabaseSnapshot(EntityKey key)
		{
			object snapshot;
			if (!entitySnapshotsByKey.TryGetValue(key, out snapshot))
				return null;

			if (snapshot == NoRow)
			{
				throw new HibernateException("persistence context reported no row snapshot for " + MessageHelper.InfoString(key.EntityName, key.Identifier));
			}
			return (object[])snapshot;
		}
Beispiel #31
0
		private IList DoQuery(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies)
		{
			RowSelection selection = queryParameters.RowSelection;
			int maxRows = HasMaxRows(selection) ? selection.MaxRows : int.MaxValue;

			int entitySpan = EntityPersisters.Length;

			List<object> hydratedObjects = entitySpan == 0 ? null : new List<object>(entitySpan * 10);

			IDbCommand st = PrepareQueryCommand(queryParameters, false, session);

			IDataReader rs = GetResultSet(st, queryParameters.HasAutoDiscoverScalarTypes, queryParameters.Callable, selection,
			                              session);

			// would be great to move all this below here into another method that could also be used
			// from the new scrolling stuff.
			//
			// Would need to change the way the max-row stuff is handled (i.e. behind an interface) so
			// that I could do the control breaking at the means to know when to stop
			LockMode[] lockModeArray = GetLockModes(queryParameters.LockModes);
			EntityKey optionalObjectKey = GetOptionalObjectKey(queryParameters, session);

			bool createSubselects = IsSubselectLoadingEnabled;
			List<EntityKey[]> subselectResultKeys = createSubselects ? new List<EntityKey[]>() : null;
			IList results = new List<object>();

			try
			{
				HandleEmptyCollections(queryParameters.CollectionKeys, rs, session);
				EntityKey[] keys = new EntityKey[entitySpan]; // we can reuse it each time

				if (log.IsDebugEnabled)
				{
					log.Debug("processing result set");
				}

				int count;
				for (count = 0; count < maxRows && rs.Read(); count++)
				{
					if (log.IsDebugEnabled)
					{
						log.Debug("result set row: " + count);
					}

					object result = GetRowFromResultSet(rs, session, queryParameters, lockModeArray, optionalObjectKey, hydratedObjects,
					                                    keys, returnProxies);
					results.Add(result);

					if (createSubselects)
					{
						subselectResultKeys.Add(keys);
						keys = new EntityKey[entitySpan]; //can't reuse in this case
					}
				}

				if (log.IsDebugEnabled)
				{
					log.Debug(string.Format("done processing result set ({0} rows)", count));
				}
			}
			catch (Exception e)
			{
				e.Data["actual-sql-query"] = st.CommandText;
				throw;
			}
			finally
			{
				session.Batcher.CloseCommand(st, rs);
			}

			InitializeEntitiesAndCollections(hydratedObjects, rs, session, queryParameters.ReadOnly);

			if (createSubselects)
			{
				CreateSubselects(subselectResultKeys, queryParameters, session);
			}

			return results;
		}
		/// <summary> Add a canonical mapping from entity key to entity instance</summary>
		public void AddEntity(EntityKey key, object entity)
		{
			entitiesByKey[key] = entity;
			BatchFetchQueue.RemoveBatchLoadableEntityKey(key);
		}
Beispiel #33
0
		/// <summary>
		/// Resolve any ids for currently loaded objects, duplications within the <c>IDataReader</c>,
		/// etc. Instanciate empty objects to be initialized from the <c>IDataReader</c>. Return an
		/// array of objects (a row of results) and an array of booleans (by side-effect) that determine
		/// wheter the corresponding object should be initialized
		/// </summary>
		private object[] GetRow(IDataReader rs, ILoadable[] persisters, EntityKey[] keys, object optionalObject,
		                        EntityKey optionalObjectKey, LockMode[] lockModes, IList hydratedObjects,
		                        ISessionImplementor session)
		{
			int cols = persisters.Length;
			IEntityAliases[] descriptors = EntityAliases;

			if (log.IsDebugEnabled)
			{
				log.Debug("result row: " + StringHelper.ToString(keys));
			}

			object[] rowResults = new object[cols];

			for (int i = 0; i < cols; i++)
			{
				object obj = null;
				EntityKey key = keys[i];

				if (keys[i] == null)
				{
					// do nothing
					/* TODO NH-1001 : if (persisters[i]...EntityType) is an OneToMany or a ManyToOne and
					 * the keys.length > 1 and the relation IsIgnoreNotFound probably we are in presence of
					 * an load with "outer join" the relation can be considerer loaded even if the key is null (mean not found)
					*/
				}
				else
				{
					//If the object is already loaded, return the loaded one
					obj = session.GetEntityUsingInterceptor(key);
					if (obj != null)
					{
						//its already loaded so dont need to hydrate it
						InstanceAlreadyLoaded(rs, i, persisters[i], key, obj, lockModes[i], session);
					}
					else
					{
						obj =
							InstanceNotYetLoaded(rs, i, persisters[i], key, lockModes[i], descriptors[i].RowIdAlias, optionalObjectKey,
							                     optionalObject, hydratedObjects, session);
					}
				}

				rowResults[i] = obj;
			}
			return rowResults;
		}
		/// <summary> 
		/// Get the entity instance associated with the given <tt>EntityKey</tt>
		/// </summary>
		public object GetEntity(EntityKey key)
		{
			object result;
			entitiesByKey.TryGetValue(key, out result);
			return result;
		}
Beispiel #35
0
		/// <summary>
		/// The entity instance is not in the session cache
		/// </summary>
		private object InstanceNotYetLoaded(IDataReader dr, int i, ILoadable persister, EntityKey key, LockMode lockMode,
		                                    string rowIdAlias, EntityKey optionalObjectKey, object optionalObject,
		                                    IList hydratedObjects, ISessionImplementor session)
		{
			object obj;

			string instanceClass = GetInstanceClass(dr, i, persister, key.Identifier, session);

			if (optionalObjectKey != null && key.Equals(optionalObjectKey))
			{
				// its the given optional object
				obj = optionalObject;
			}
			else
			{
				obj = session.Instantiate(instanceClass, key.Identifier);
			}

			// need to hydrate it

			// grab its state from the DataReader and keep it in the Session
			// (but don't yet initialize the object itself)
			// note that we acquired LockMode.READ even if it was not requested
			LockMode acquiredLockMode = lockMode == LockMode.None ? LockMode.Read : lockMode;
			LoadFromResultSet(dr, i, obj, instanceClass, key, rowIdAlias, acquiredLockMode, persister, session);

			// materialize associations (and initialize the object) later
			hydratedObjects.Add(obj);

			return obj;
		}
		/// <summary> Is there an entity with the given key in the persistence context</summary>
		public bool ContainsEntity(EntityKey key)
		{
			return entitiesByKey.ContainsKey(key);
		}
		/// <summary>
		/// Return the Underlying Persistent Object in a given <see cref="ISession"/>, or null.
		/// </summary>
		/// <param name="s">The Session to get the object from.</param>
		/// <returns>The Persistent Object this proxy is Proxying, or <see langword="null" />.</returns>
		public object GetImplementation(ISessionImplementor s)
		{
			EntityKey key = new EntityKey(Identifier, s.Factory.GetEntityPersister(EntityName), s.EntityMode);
			return s.PersistenceContext.GetEntity(key);
		}
		/// <summary> 
		/// Remove an entity from the session cache, also clear
		/// up other state associated with the entity, all except
		/// for the <tt>EntityEntry</tt>
		/// </summary>
		public object RemoveEntity(EntityKey key)
		{
			object tempObject = entitiesByKey[key];
			entitiesByKey.Remove(key);
			object entity = tempObject;
			List<EntityUniqueKey> toRemove = new List<EntityUniqueKey>();
			foreach (KeyValuePair<EntityUniqueKey, object> pair in entitiesByUniqueKey)
			{
				if (pair.Value == entity) toRemove.Add(pair.Key);
			}
			foreach (EntityUniqueKey uniqueKey in toRemove)
			{
				entitiesByUniqueKey.Remove(uniqueKey);
			}

			entitySnapshotsByKey.Remove(key);
			nullifiableEntityKeys.Remove(key);
			BatchFetchQueue.RemoveBatchLoadableEntityKey(key);
			BatchFetchQueue.RemoveSubselect(key);
			return entity;
		}