Пример #1
0
        public override bool IsEqual(object x, object y, ISessionFactoryImplementor factory)
        {
            IEntityPersister persister = factory.GetEntityPersister(associatedEntityName);

            if (!persister.CanExtractIdOutOfEntity)
            {
                return(base.IsEqual(x, y));
            }

            object xid;

            if (x.IsProxy())
            {
                INHibernateProxy proxy = x as INHibernateProxy;
                xid = proxy.HibernateLazyInitializer.Identifier;
            }
            else
            {
                xid = persister.GetIdentifier(x);
            }

            object yid;

            if (y.IsProxy())
            {
                INHibernateProxy proxy = y as INHibernateProxy;
                yid = proxy.HibernateLazyInitializer.Identifier;
            }
            else
            {
                yid = persister.GetIdentifier(y);
            }

            return(persister.IdentifierType.IsEqual(xid, yid, factory));
        }
Пример #2
0
        /// <summary>
        /// Is this instance, which we know is not persistent, actually transient?
        /// If <tt>assumed</tt> is non-null, don't hit the database to make the
        /// determination, instead assume that value; the client code must be
        /// prepared to "recover" in the case that this assumed result is incorrect.
        /// </summary>
        /// <remarks>
        /// If <paramref name="assumed"/> is non-null, don't hit the database to make the
        /// determination, instead assume that value; the client code must be
        /// prepared to "recover" in the case that this assumed result is incorrect.
        /// </remarks>
        public static bool IsTransient(string entityName, object entity, bool?assumed, ISessionImplementor session)
        {
            if (entity == Intercept.LazyPropertyInitializer.UnfetchedProperty)
            {
                // an unfetched association can only point to
                // an entity that already exists in the db
                return(false);
            }

            // let the interceptor inspect the instance to decide
            bool?isUnsaved = session.Interceptor.IsTransient(entity);

            if (isUnsaved.HasValue)
            {
                return(isUnsaved.Value);
            }

            // let the persister inspect the instance to decide
            IEntityPersister persister = session.GetEntityPersister(entityName, entity);

            isUnsaved = persister.IsTransient(entity, session);
            if (isUnsaved.HasValue)
            {
                return(isUnsaved.Value);
            }

            // we use the assumed value, if there is one, to avoid hitting
            // the database
            if (assumed.HasValue)
            {
                return(assumed.Value);
            }

            if (persister.IdentifierGenerator is Assigned)
            {
                // When using assigned identifiers we cannot tell if an entity
                // is transient or detached without querying the database.
                // This could potentially cause Select N+1 in cascaded saves, so warn the user.
                log.Warn("Unable to determine if " + entity.ToString()
                         + " with assigned identifier " + persister.GetIdentifier(entity, session.EntityMode)
                         + " is transient or detached; querying the database."
                         + " Use explicit Save() or Update() in session to prevent this.");
            }

            // hit the database, after checking the session cache for a snapshot
            System.Object[] snapshot =
                session.PersistenceContext.GetDatabaseSnapshot(persister.GetIdentifier(entity, session.EntityMode), persister);
            return(snapshot == null);
        }
        private static bool ExistsInDatabase(object entity, IEventSource source, IEntityPersister persister)
        {
            EntityEntry entry = source.PersistenceContext.GetEntry(entity);

            if (entry == null)
            {
                object id = persister.GetIdentifier(entity, source.EntityMode);
                if (id != null)
                {
                    EntityKey key           = source.GenerateEntityKey(id, persister);
                    object    managedEntity = source.PersistenceContext.GetEntity(key);
                    entry = source.PersistenceContext.GetEntry(managedEntity);
                }
            }

            if (entry == null)
            {
                // perhaps this should be an exception since it is only ever used
                // in the above method?
                return(false);
            }
            else
            {
                return(entry.ExistsInDatabase);
            }
        }
Пример #4
0
        /// <summary>
        /// Get the id value from the owning entity key, usually the same as the key, but might be some
        /// other property, in the case of property-ref
        /// </summary>
        /// <param name="key">The collection owner key </param>
        /// <param name="session">The session from which the request is originating. </param>
        /// <returns>
        /// The collection owner's id, if it can be obtained from the key;
        /// otherwise, null is returned
        /// </returns>
        public virtual object GetIdOfOwnerOrNull(object key, ISessionImplementor session)
        {
            object ownerId = null;

            if (foreignKeyPropertyName == null)
            {
                ownerId = key;
            }
            else
            {
                IType            keyType        = GetPersister(session).KeyType;
                IEntityPersister ownerPersister = GetPersister(session).OwnerEntityPersister;
                // TODO: Fix this so it will work for non-POJO entity mode
                System.Type ownerMappedClass = ownerPersister.GetMappedClass(session.EntityMode);
                if (ownerMappedClass.IsAssignableFrom(keyType.ReturnedClass) && keyType.ReturnedClass.IsInstanceOfType(key))
                {
                    // the key is the owning entity itself, so get the ID from the key
                    ownerId = ownerPersister.GetIdentifier(key, session.EntityMode);
                }
                else
                {
                    // TODO: check if key contains the owner ID
                }
            }
            return(ownerId);
        }
Пример #5
0
        static bool HasDbSnapshot(string entityName, object entity, ISessionImplementor session)
        {
            IEntityPersister persister = session.GetEntityPersister(entityName, entity);

            if (persister.IdentifierGenerator is Assigned)
            {
                // When using assigned identifiers we cannot tell if an entity
                // is transient or detached without querying the database.
                // This could potentially cause Select N+1 in cascaded saves, so warn the user.
                log.Warn("Unable to determine if {0} with assigned identifier {1} is transient or detached; querying the database. Use explicit Save() or Update() in session to prevent this.",
                         entity, persister.GetIdentifier(entity));
            }

            // hit the database, after checking the session cache for a snapshot
            System.Object[] snapshot =
                session.PersistenceContext.GetDatabaseSnapshot(persister.GetIdentifier(entity), persister);
            return(snapshot == null);
        }
Пример #6
0
 /// <summary> Delete a entity. </summary>
 /// <param name="entityName">The entityName for the entity to be deleted </param>
 /// <param name="entity">a detached entity instance </param>
 public void Delete(string entityName, object entity)
 {
     using (BeginProcess())
     {
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object           version   = persister.GetVersion(entity);
         persister.Delete(id, version, entity, this);
     }
 }
Пример #7
0
 /// <summary> Delete a entity. </summary>
 /// <param name="entityName">The entityName for the entity to be deleted </param>
 /// <param name="entity">a detached entity instance </param>
 public void Delete(string entityName, object entity)
 {
     using (new SessionIdLoggingContext(SessionId))
     {
         CheckAndUpdateSessionStatus();
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object           version   = persister.GetVersion(entity);
         persister.Delete(id, version, entity, this);
     }
 }
Пример #8
0
 /// <summary> Delete a entity. </summary>
 /// <param name="entityName">The entityName for the entity to be deleted </param>
 /// <param name="entity">a detached entity instance </param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
 public async Task DeleteAsync(string entityName, object entity, CancellationToken cancellationToken = default(CancellationToken))
 {
     cancellationToken.ThrowIfCancellationRequested();
     using (BeginProcess())
     {
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object           version   = persister.GetVersion(entity);
         await(persister.DeleteAsync(id, version, entity, this, cancellationToken)).ConfigureAwait(false);
     }
 }
Пример #9
0
 /// <summary> Delete a entity. </summary>
 /// <param name="entityName">The entityName for the entity to be deleted </param>
 /// <param name="entity">a detached entity instance </param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
 public async Task DeleteAsync(string entityName, object entity, CancellationToken cancellationToken = default(CancellationToken))
 {
     cancellationToken.ThrowIfCancellationRequested();
     using (new SessionIdLoggingContext(SessionId))
     {
         CheckAndUpdateSessionStatus();
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object           version   = persister.GetVersion(entity);
         await(persister.DeleteAsync(id, version, entity, this, cancellationToken)).ConfigureAwait(false);
     }
 }
Пример #10
0
        static async Task <bool> HasDbSnapshotAsync(string entityName, object entity, ISessionImplementor session, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEntityPersister persister = session.GetEntityPersister(entityName, entity);

            if (persister.IdentifierGenerator is Assigned)
            {
                // When using assigned identifiers we cannot tell if an entity
                // is transient or detached without querying the database.
                // This could potentially cause Select N+1 in cascaded saves, so warn the user.
                log.Warn(
                    "Unable to determine if " + entity.ToString()
                    + " with assigned identifier " + persister.GetIdentifier(entity)
                    + " is transient or detached; querying the database."
                    + " Use explicit Save() or Update() in session to prevent this.");
            }

            // hit the database, after checking the session cache for a snapshot
            System.Object[] snapshot =
                await(session.PersistenceContext.GetDatabaseSnapshotAsync(persister.GetIdentifier(entity), persister, cancellationToken)).ConfigureAwait(false);
            return(snapshot == null);
        }
        public static T Attach <T>(this ISession session, T entity, LockMode mode = null)
        {
            mode = mode ?? LockMode.None;

            IEntityPersister persister = session.GetSessionImplementation().GetEntityPersister(NHibernateProxyHelper.GuessClass(entity).FullName, entity);

            Object[]    fields  = persister.GetPropertyValues(entity, session.ActiveEntityMode);
            Object      id      = persister.GetIdentifier(entity, session.ActiveEntityMode);
            Object      version = persister.GetVersion(entity, session.ActiveEntityMode);
            EntityEntry entry   = session.GetSessionImplementation().PersistenceContext.AddEntry(entity, Status.Loaded, fields, null, id, version, LockMode.None, true, persister, true, false);

            return(entity);
        }
Пример #12
0
        /// <summary>
        /// Get the identifier value of an instance or proxy.
        /// <p/>
        /// Intended only for loggin purposes!!!
        /// </summary>
        /// <param name="obj">The object from which to extract the identifier.</param>
        /// <param name="persister">The entity persister </param>
        /// <returns> The extracted identifier. </returns>
        private static object GetIdentifier(object obj, IEntityPersister persister)
        {
            if (obj.IsProxy())
            {
                INHibernateProxy proxy = obj as INHibernateProxy;
                ILazyInitializer li    = proxy.HibernateLazyInitializer;

                return(li.Identifier);
            }
            else
            {
                return(persister.GetIdentifier(obj));
            }
        }
Пример #13
0
        /// <summary>Handle the given lock event. </summary>
        /// <param name="event">The lock event to be handled.</param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        public virtual Task OnLockAsync(LockEvent @event, CancellationToken cancellationToken)
        {
            if (@event.Entity == null)
            {
                throw new NullReferenceException("attempted to lock null");
            }

            if (@event.LockMode == LockMode.Write)
            {
                throw new HibernateException("Invalid lock mode for lock()");
            }
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            return(InternalOnLockAsync());

            async Task InternalOnLockAsync()
            {
                ISessionImplementor source = @event.Session;

                if (@event.LockMode == LockMode.None && source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity))
                {
                    // NH-specific: shortcut for uninitialized proxies - reassociate
                    // without initialization
                    return;
                }

                object entity = await(source.PersistenceContext.UnproxyAndReassociateAsync(@event.Entity, cancellationToken)).ConfigureAwait(false);
                //TODO: if object was an uninitialized proxy, this is inefficient,resulting in two SQL selects

                EntityEntry entry = source.PersistenceContext.GetEntry(entity);

                if (entry == null)
                {
                    IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);
                    object           id        = persister.GetIdentifier(entity);
                    if ((await(ForeignKeys.IsTransientFastAsync(@event.EntityName, entity, source, cancellationToken)).ConfigureAwait(false)).GetValueOrDefault())
                    {
                        throw new TransientObjectException("cannot lock an unsaved transient instance: " + persister.EntityName);
                    }

                    entry = await(ReassociateAsync(@event, entity, id, persister, cancellationToken)).ConfigureAwait(false);

                    await(CascadeOnLockAsync(@event, persister, entity, cancellationToken)).ConfigureAwait(false);
                }

                await(UpgradeLockAsync(entity, entry, @event.LockMode, source, cancellationToken)).ConfigureAwait(false);
            }
        }
Пример #14
0
        /// <summary>
        /// Get the identifier value of an instance or proxy.
        /// <p/>
        /// Intended only for loggin purposes!!!
        /// </summary>
        /// <param name="obj">The object from which to extract the identifier.</param>
        /// <param name="persister">The entity persister </param>
        /// <param name="entityMode">The entity mode </param>
        /// <returns> The extracted identifier. </returns>
        private static object GetIdentifier(object obj, IEntityPersister persister, EntityMode entityMode)
        {
            INHibernateProxy proxy = obj as INHibernateProxy;

            if (proxy != null)
            {
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                return(li.Identifier);
            }
            else
            {
                return(persister.GetIdentifier(obj, entityMode));
            }
        }
Пример #15
0
        public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
        {
            //we only need this for SQL Server, and or large amount of values
            if ((criteriaQuery.Factory.Dialect is MsSql2005Dialect) == false || values.Length < maximumNumberOfParametersToNotUseXml)
            {
                return(expr.GetTypedValues(criteria, criteriaQuery));
            }

            IEntityPersister persister = null;
            IType            type      = criteriaQuery.GetTypeUsingProjection(criteria, propertyName);

            if (type.IsEntityType)
            {
                persister = criteriaQuery.Factory.GetEntityPersister(type.ReturnedClass.FullName);
            }
            StringWriter      sw = new StringWriter();
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();

            xmlWriterSettings.Encoding = System.Text.Encoding.UTF8;

            XmlWriter writer = XmlWriter.Create(sw, xmlWriterSettings);

            writer.WriteStartElement("items");
            foreach (object value in values)
            {
                if (value == null)
                {
                    continue;
                }
                object valToWrite;
                if (persister != null)
                {
                    valToWrite = persister.GetIdentifier(value);
                }
                else
                {
                    valToWrite = value;
                }
                writer.WriteElementString("val", valToWrite.ToString());
            }
            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();
            string xmlString = sw.GetStringBuilder().ToString();

            return(new TypedValue[] {
                new TypedValue(new CustomType(typeof(XmlType),
                                              new Dictionary <string, string>()), xmlString),
            });
        }
        /// <summary> Determine the id to use for updating. </summary>
        /// <param name="entity">The entity. </param>
        /// <param name="persister">The entity persister </param>
        /// <param name="requestedId">The requested identifier </param>
        /// <returns> The id. </returns>
        protected virtual object GetUpdateId(object entity, IEntityPersister persister, object requestedId)
        {
            // use the id assigned to the instance
            object id = persister.GetIdentifier(entity);

            if (id == null)
            {
                // assume this is a newly instantiated transient object
                // which should be saved rather than updated
                throw new TransientObjectException("The given object has a null identifier: " + persister.EntityName);
            }
            else
            {
                return(id);
            }
        }
Пример #17
0
        /// <summary>
        /// Refresh the entity instance state from the database.
        /// </summary>
        /// <param name="entityName">The entityName for the entity to be refreshed. </param>
        /// <param name="entity">The entity to be refreshed. </param>
        /// <param name="lockMode">The LockMode to be applied. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        public async Task RefreshAsync(string entityName, object entity, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            using (BeginProcess())
            {
                // We need to flush the batcher. Otherwise it may have pending operations which will not already have reached the database,
                // and the query may yield stale data.
                await(FlushAsync(cancellationToken)).ConfigureAwait(false);

                IEntityPersister persister = GetEntityPersister(entityName, entity);
                object           id        = persister.GetIdentifier(entity);
                if (log.IsDebugEnabled())
                {
                    log.Debug("refreshing transient {0}", MessageHelper.InfoString(persister, id, Factory));
                }
                //from H3.2 TODO : can this ever happen???
                //		EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
                //		if ( source.getPersistenceContext().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.getFactory() )
                //			);
                //		}

                if (persister.HasCache)
                {
                    CacheKey ck = GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
                    await(persister.Cache.RemoveAsync(ck, cancellationToken)).ConfigureAwait(false);
                }

                string previousFetchProfile = FetchProfile;
                object result;
                try
                {
                    FetchProfile = "refresh";
                    result       = await(persister.LoadAsync(id, entity, lockMode, this, cancellationToken)).ConfigureAwait(false);
                }
                finally
                {
                    FetchProfile = previousFetchProfile;
                }
                UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName);
            }
        }
        protected virtual void EntityIsTransient(MergeEvent @event, IDictionary copyCache)
        {
            log.Debug("merging transient instance");

            object       entity = @event.Entity;
            IEventSource source = @event.Session;

            IEntityPersister persister  = source.GetEntityPersister(@event.EntityName, entity);
            string           entityName = persister.EntityName;

            object id = persister.HasIdentifierProperty ? persister.GetIdentifier(entity, source.EntityMode) : null;

            object copy = persister.Instantiate(id, source.EntityMode); // should this be Session.instantiate(Persister, ...)?

            copyCache[entity] = copy;                                   //before cascade!

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
            base.CascadeBeforeSave(source, persister, entity, copyCache);
            CopyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyFromParent);

            //this bit is only *really* absolutely necessary for handling
            //requestedId, but is also good if we merge multiple object
            //graphs, since it helps ensure uniqueness
            object requestedId = @event.RequestedId;

            if (requestedId == null)
            {
                SaveWithGeneratedId(copy, entityName, copyCache, source, false);
            }
            else
            {
                SaveWithRequestedId(copy, requestedId, entityName, copyCache, source);
            }

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            base.CascadeAfterSave(source, persister, entity, copyCache);
            CopyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyToParent);

            @event.Result = copy;
        }
        /// <summary>Handle the given lock event. </summary>
        /// <param name="event">The lock event to be handled.</param>
        public virtual void OnLock(LockEvent @event)
        {
            if (@event.Entity == null)
            {
                throw new NullReferenceException("attempted to lock null");
            }

            if (@event.LockMode == LockMode.Write)
            {
                throw new HibernateException("Invalid lock mode for lock()");
            }

            ISessionImplementor source = @event.Session;

            if (@event.LockMode == LockMode.None && source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity))
            {
                // NH-specific: shortcut for uninitialized proxies - reassociate
                // without initialization
                return;
            }

            object entity = source.PersistenceContext.UnproxyAndReassociate(@event.Entity);
            //TODO: if object was an uninitialized proxy, this is inefficient,resulting in two SQL selects

            EntityEntry entry = source.PersistenceContext.GetEntry(entity);

            if (entry == null)
            {
                IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);
                object           id        = persister.GetIdentifier(entity);
                if (!ForeignKeys.IsNotTransient(@event.EntityName, entity, false, source))
                {
                    throw new TransientObjectException("cannot lock an unsaved transient instance: " + persister.EntityName);
                }

                entry = Reassociate(@event, entity, id, persister);

                CascadeOnLock(@event, persister, entity);
            }

            UpgradeLock(entity, entry, @event.LockMode, source);
        }
Пример #20
0
        public IFuturo <T> GetFuturo <T>(Guid id) where T : EntityBase
        {
            var tarea = Task.Run(() =>
            {
                T entidad = null;
                using (var sessionStateless = _session.SessionFactory.OpenStatelessSession())
                {
                    entidad = sessionStateless.Get <T>(id);
                }

                IEntityPersister persister = _session.GetSessionImplementation().GetEntityPersister(NHibernateProxyHelper.GuessClass(entidad).FullName, entidad);
                object[] fields            = persister.GetPropertyValues(entidad, _session.ActiveEntityMode);
                object oid        = persister.GetIdentifier(entidad, _session.ActiveEntityMode);
                EntityEntry entry = _session.GetSessionImplementation().PersistenceContext.AddEntry(entidad, Status.Loaded, fields, null, id, null, LockMode.None, true, persister, true, false);

                return(entidad);
            });

            _tareas.Add(tarea);
            return(new Futuro <T>(tarea));
        }
Пример #21
0
        /// <summary>
        /// Refresh the entity instance state from the database.
        /// </summary>
        /// <param name="entityName">The entityName for the entity to be refreshed. </param>
        /// <param name="entity">The entity to be refreshed. </param>
        /// <param name="lockMode">The LockMode to be applied. </param>
        public void Refresh(string entityName, object entity, LockMode lockMode)
        {
            using (new SessionIdLoggingContext(SessionId))
            {
                IEntityPersister persister = GetEntityPersister(entityName, entity);
                object           id        = persister.GetIdentifier(entity);
                if (log.IsDebugEnabled)
                {
                    log.Debug("refreshing transient " + MessageHelper.InfoString(persister, id, Factory));
                }
                //from H3.2 TODO : can this ever happen???
                //		EntityKey key = new EntityKey( id, persister, source.getEntityMode() );
                //		if ( source.getPersistenceContext().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.getFactory() )
                //			);
                //		}

                if (persister.HasCache)
                {
                    CacheKey ck = GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
                    persister.Cache.Remove(ck);
                }

                string previousFetchProfile = FetchProfile;
                object result;
                try
                {
                    FetchProfile = "refresh";
                    result       = persister.Load(id, entity, lockMode, this);
                }
                finally
                {
                    FetchProfile = previousFetchProfile;
                }
                UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName);
            }
        }
Пример #22
0
        /// <summary>
        /// make sure user didn't mangle the id
        /// </summary>
        /// <param name="obj">The obj.</param>
        /// <param name="persister">The persister.</param>
        /// <param name="id">The id.</param>
        /// <param name="entityMode">The entity mode.</param>
        public virtual void CheckId(object obj, IEntityPersister persister, object id, EntityMode entityMode)
        {
            if (id != null && id is DelayedPostInsertIdentifier)
            {
                // this is a situation where the entity id is assigned by a post-insert generator
                // and was saved outside the transaction forcing it to be delayed
                return;
            }

            if (persister.CanExtractIdOutOfEntity)
            {
                object oid = persister.GetIdentifier(obj, entityMode);
                if (id == null)
                {
                    throw new AssertionFailure("null id in " + persister.EntityName + " entry (don't flush the Session after an exception occurs)");
                }
                if (!persister.IdentifierType.IsEqual(id, oid, EntityMode.Poco))
                {
                    throw new HibernateException("identifier of an instance of " + persister.EntityName + " was altered from " + id + " to " + oid);
                }
            }
        }
        /// <summary>
        /// make sure user didn't mangle the id
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="persister"></param>
        /// <param name="id"></param>
        /// <param name="entityMode"></param>
        public virtual void CheckId(object obj, IEntityPersister persister, object id, EntityMode entityMode)
        {
            if (id != null && id is DelayedPostInsertIdentifier)
            {
                // this is a situation where the entity id is assigned by a post-insert generator
                // and was saved outside the transaction forcing it to be delayed
                return;
            }

            if (persister.CanExtractIdOutOfEntity)
            {
                object oid = persister.GetIdentifier(obj, entityMode);
                if (id == null)
                {
                    throw new AssertionFailure("null id in " + persister.EntityName + " entry (don't flush the Session after an exception occurs)");
                }
                if (!persister.IdentifierType.IsEqual(id, oid, EntityMode.Poco))
                {
                    throw new HibernateException("identifier of an instance of " + persister.EntityName + " was altered from " + id + " to " + oid);
                }
            }
        }
Пример #24
0
 /// <summary>Update a entity.</summary>
 /// <param name="entityName">The entityName for the entity to be updated </param>
 /// <param name="entity">a detached entity instance </param>
 public void Update(string entityName, object entity)
 {
     using (BeginProcess())
     {
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object[]         state     = persister.GetPropertyValues(entity);
         object           oldVersion;
         if (persister.IsVersioned)
         {
             oldVersion = persister.GetVersion(entity);
             object newVersion = Versioning.Increment(oldVersion, persister.VersionType, this);
             Versioning.SetVersion(state, newVersion, persister);
             persister.SetPropertyValues(entity, state);
         }
         else
         {
             oldVersion = null;
         }
         persister.Update(id, state, null, false, null, oldVersion, entity, null, this);
     }
 }
Пример #25
0
        public override int GetHashCode(object x, ISessionFactoryImplementor factory)
        {
            IEntityPersister persister = factory.GetEntityPersister(associatedEntityName);

            if (!persister.CanExtractIdOutOfEntity)
            {
                return(base.GetHashCode(x));
            }

            object id;

            if (x.IsProxy())
            {
                INHibernateProxy proxy = x as INHibernateProxy;
                id = proxy.HibernateLazyInitializer.Identifier;
            }
            else
            {
                id = persister.GetIdentifier(x);
            }
            return(persister.IdentifierType.GetHashCode(id, factory));
        }
 /// <summary>Update a entity.</summary>
 /// <param name="entityName">The entityName for the entity to be updated </param>
 /// <param name="entity">a detached entity instance </param>
 public void Update(string entityName, object entity)
 {
     using (new SessionIdLoggingContext(SessionId))
     {
         CheckAndUpdateSessionStatus();
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity, EntityMode.Poco);
         object[]         state     = persister.GetPropertyValues(entity, EntityMode.Poco);
         object           oldVersion;
         if (persister.IsVersioned)
         {
             oldVersion = persister.GetVersion(entity, EntityMode.Poco);
             object newVersion = Versioning.Increment(oldVersion, persister.VersionType, this);
             Versioning.SetVersion(state, newVersion, persister);
             persister.SetPropertyValues(entity, state, EntityMode.Poco);
         }
         else
         {
             oldVersion = null;
         }
         persister.Update(id, state, null, false, null, oldVersion, entity, null, this);
     }
 }
Пример #27
0
 /// <summary>Update a entity.</summary>
 /// <param name="entityName">The entityName for the entity to be updated </param>
 /// <param name="entity">a detached entity instance </param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
 public async Task UpdateAsync(string entityName, object entity, CancellationToken cancellationToken = default(CancellationToken))
 {
     cancellationToken.ThrowIfCancellationRequested();
     using (BeginProcess())
     {
         IEntityPersister persister = GetEntityPersister(entityName, entity);
         object           id        = persister.GetIdentifier(entity);
         object[]         state     = persister.GetPropertyValues(entity);
         object           oldVersion;
         if (persister.IsVersioned)
         {
             oldVersion = persister.GetVersion(entity);
             object newVersion = await(Versioning.IncrementAsync(oldVersion, persister.VersionType, this, cancellationToken)).ConfigureAwait(false);
             Versioning.SetVersion(state, newVersion, persister);
             persister.SetPropertyValues(entity, state);
         }
         else
         {
             oldVersion = null;
         }
         await(persister.UpdateAsync(id, state, null, false, null, oldVersion, entity, null, this, cancellationToken)).ConfigureAwait(false);
     }
 }
		public static object GetIdentifier(object obj, IEntityPersister persister)
		{
			if (obj is INHibernateProxy)
			{
				INHibernateProxy proxy = (INHibernateProxy) obj;
				LazyInitializer li = GetLazyInitializer(proxy);
				return li.Identifier;
			}
			else
			{
				return persister.GetIdentifier(obj);
			}
		}
        public virtual async Task OnReplicateAsync(ReplicateEvent @event, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEventSource source = @event.Session;

            if (source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity))
            {
                log.Debug("uninitialized proxy passed to replicate()");
                return;
            }

            object entity = await(source.PersistenceContext.UnproxyAndReassociateAsync(@event.Entity, cancellationToken)).ConfigureAwait(false);

            if (source.PersistenceContext.IsEntryFor(entity))
            {
                log.Debug("ignoring persistent instance passed to replicate()");
                //hum ... should we cascade anyway? throw an exception? fine like it is?
                return;
            }

            IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);

            // get the id from the object

            /*if ( persister.isUnsaved(entity, source) ) {
             * throw new TransientObjectException("transient instance passed to replicate()");
             * }*/
            object id = persister.GetIdentifier(entity);

            if (id == null)
            {
                throw new TransientObjectException("instance with null id passed to replicate()");
            }

            ReplicationMode replicationMode = @event.ReplicationMode;
            object          oldVersion;

            if (replicationMode == ReplicationMode.Exception)
            {
                //always do an INSERT, and let it fail by constraint violation
                oldVersion = null;
            }
            else
            {
                //what is the version on the database?
                oldVersion = await(persister.GetCurrentVersionAsync(id, source, cancellationToken)).ConfigureAwait(false);
            }

            if (oldVersion != null)
            {
                if (log.IsDebugEnabled())
                {
                    log.Debug("found existing row for {0}", MessageHelper.InfoString(persister, id, source.Factory));
                }

                // HHH-2378
                object realOldVersion = persister.IsVersioned ? oldVersion : null;

                bool canReplicate =
                    replicationMode.ShouldOverwriteCurrentVersion(entity, realOldVersion,
                                                                  persister.GetVersion(entity),
                                                                  persister.VersionType);

                if (canReplicate)
                {
                    //will result in a SQL UPDATE:
                    await(PerformReplicationAsync(entity, id, realOldVersion, persister, replicationMode, source, cancellationToken)).ConfigureAwait(false);
                }
                else
                {
                    //else do nothing (don't even reassociate object!)
                    log.Debug("no need to replicate");
                }

                //TODO: would it be better to do a refresh from db?
            }
            else
            {
                // no existing row - do an insert
                if (log.IsDebugEnabled())
                {
                    log.Debug("no existing row, replicating new instance {0}", MessageHelper.InfoString(persister, id, source.Factory));
                }

                bool      regenerate = persister.IsIdentifierAssignedByInsert;            // prefer re-generation of identity!
                EntityKey key        = regenerate ? null : source.GenerateEntityKey(id, persister);

                await(PerformSaveOrReplicateAsync(entity, key, persister, regenerate, replicationMode, source, true, cancellationToken)).ConfigureAwait(false);
            }
        }
Пример #30
0
        private async Task <object> MergeTransientEntityAsync(object entity, string entityName, object requestedId, IEventSource source, IDictionary copyCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEntityPersister persister = source.GetEntityPersister(entityName, entity);

            object id   = persister.HasIdentifierProperty ? persister.GetIdentifier(entity) : null;
            object copy = null;

            if (copyCache.Contains(entity))
            {
                copy = copyCache[entity];
                persister.SetIdentifier(copy, id);
            }
            else
            {
                copy = source.Instantiate(persister, id);
                ((EventCache)copyCache).Add(entity, copy, true);                 // before cascade!
            }

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            //cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
            await(base.CascadeBeforeSaveAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
            await(CopyValuesAsync(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyFromParent, cancellationToken)).ConfigureAwait(false);

            try
            {
                // try saving; check for non-nullable properties that are null or transient entities before saving
                await(this.SaveTransientEntityAsync(copy, entityName, requestedId, source, copyCache, cancellationToken)).ConfigureAwait(false);
            }
            catch (PropertyValueException ex)
            {
                string      propertyName       = ex.PropertyName;
                object      propertyFromCopy   = persister.GetPropertyValue(copy, propertyName);
                object      propertyFromEntity = persister.GetPropertyValue(entity, propertyName);
                IType       propertyType       = persister.GetPropertyType(propertyName);
                EntityEntry copyEntry          = source.PersistenceContext.GetEntry(copy);

                if (propertyFromCopy == null || !propertyType.IsEntityType)
                {
                    log.Info("property '{0}.{1}' is null or not an entity; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromCopy);
                    throw;
                }

                if (!copyCache.Contains(propertyFromEntity))
                {
                    log.Info("property '{0}.{1}' from original entity is not in copyCache; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                    throw;
                }

                if (((EventCache)copyCache).IsOperatedOn(propertyFromEntity))
                {
                    log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                }
                else
                {
                    log.Info(ex, "property '{0}.{1}' from original entity is in copyCache and is not in the process of being merged; {1} =[{2}]", copyEntry.EntityName, propertyName, propertyFromEntity);
                }

                // continue...; we'll find out if it ends up not getting saved later
            }

            // cascade first, so that all unsaved objects get their
            // copy created before we actually copy
            await(base.CascadeAfterSaveAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
            await(CopyValuesAsync(persister, entity, copy, source, copyCache, ForeignKeyDirection.ForeignKeyToParent, cancellationToken)).ConfigureAwait(false);

            return(copy);
        }
Пример #31
0
		/// <summary> 
		/// Get the identifier value of an instance or proxy.
		/// <p/>
		/// Intended only for loggin purposes!!!
		/// </summary>
		/// <param name="obj">The object from which to extract the identifier.</param>
		/// <param name="persister">The entity persister </param>
		/// <param name="entityMode">The entity mode </param>
		/// <returns> The extracted identifier. </returns>
		private static object GetIdentifier(object obj, IEntityPersister persister, EntityMode entityMode)
		{
			if (obj.IsProxy())
			{
				INHibernateProxy proxy = obj as INHibernateProxy; 
				ILazyInitializer li = proxy.HibernateLazyInitializer;
				
				return li.Identifier;
			}
			else
			{
				return persister.GetIdentifier(obj, entityMode);
			}
		}
Пример #32
0
        protected virtual async Task EntityIsDetachedAsync(MergeEvent @event, IDictionary copyCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("merging detached instance");

            object       entity = @event.Entity;
            IEventSource source = @event.Session;

            IEntityPersister persister  = source.GetEntityPersister(@event.EntityName, entity);
            string           entityName = persister.EntityName;

            object id = @event.RequestedId;

            if (id == null)
            {
                id = persister.GetIdentifier(entity);
            }
            else
            {
                // check that entity id = requestedId
                object entityId = persister.GetIdentifier(entity);
                if (!persister.IdentifierType.IsEqual(id, entityId, source.Factory))
                {
                    throw new HibernateException("merge requested with id not matching id of passed entity");
                }
            }

            string previousFetchProfile = source.FetchProfile;

            source.FetchProfile = "merge";

            //we must clone embedded composite identifiers, or
            //we will get back the same instance that we pass in
            object clonedIdentifier = persister.IdentifierType.DeepCopy(id, source.Factory);
            object result           = await(source.GetAsync(persister.EntityName, clonedIdentifier, cancellationToken)).ConfigureAwait(false);

            source.FetchProfile = previousFetchProfile;

            if (result == null)
            {
                //TODO: we should throw an exception if we really *know* for sure
                //      that this is a detached instance, rather than just assuming
                //throw new StaleObjectStateException(entityName, id);

                // we got here because we assumed that an instance
                // with an assigned id was detached, when it was
                // really persistent
                await(EntityIsTransientAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
            }
            else
            {
                // NH different behavior : NH-1517
                if (InvokeUpdateLifecycle(entity, persister, source))
                {
                    return;
                }

                ((EventCache)copyCache).Add(entity, result, true);                 //before cascade!

                object target = source.PersistenceContext.Unproxy(result);
                if (target == entity)
                {
                    throw new AssertionFailure("entity was not detached");
                }
                else if (!(await(source.GetEntityNameAsync(target, cancellationToken)).ConfigureAwait(false)).Equals(entityName))
                {
                    throw new WrongClassException("class of the given object did not match class of persistent copy",
                                                  @event.RequestedId, persister.EntityName);
                }
                else if (IsVersionChanged(entity, source, persister, target))
                {
                    if (source.Factory.Statistics.IsStatisticsEnabled)
                    {
                        source.Factory.StatisticsImplementor.OptimisticFailure(entityName);
                    }
                    throw new StaleObjectStateException(persister.EntityName, id);
                }

                // cascade first, so that all unsaved objects get their
                // copy created before we actually copy
                await(CascadeOnMergeAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
                await(CopyValuesAsync(persister, entity, target, source, copyCache, cancellationToken)).ConfigureAwait(false);

                //copyValues works by reflection, so explicitly mark the entity instance dirty
                MarkInterceptorDirty(entity, target);

                @event.Result = result;
            }
        }
Пример #33
0
        public virtual async Task OnMergeAsync(MergeEvent @event, IDictionary copiedAlready, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            EventCache   copyCache = (EventCache)copiedAlready;
            IEventSource source    = @event.Session;
            object       original  = @event.Original;

            if (original != null)
            {
                object entity;
                if (original.IsProxy())
                {
                    ILazyInitializer li = ((INHibernateProxy)original).HibernateLazyInitializer;
                    if (li.IsUninitialized)
                    {
                        log.Debug("ignoring uninitialized proxy");
                        @event.Result = await(source.LoadAsync(li.EntityName, li.Identifier, cancellationToken)).ConfigureAwait(false);
                        return;                         //EARLY EXIT!
                    }
                    else
                    {
                        entity = await(li.GetImplementationAsync(cancellationToken)).ConfigureAwait(false);
                    }
                }
                else
                {
                    entity = original;
                }

                if (copyCache.Contains(entity) && copyCache.IsOperatedOn(entity))
                {
                    log.Debug("already in merge process");
                    @event.Result = entity;
                }
                else
                {
                    if (copyCache.Contains(entity))
                    {
                        log.Info("already in copyCache; setting in merge process");
                        copyCache.SetOperatedOn(entity, true);
                    }

                    @event.Entity = entity;
                    EntityState entityState = EntityState.Undefined;
                    if (ReferenceEquals(null, @event.EntityName))
                    {
                        @event.EntityName = source.BestGuessEntityName(entity);
                    }

                    // Check the persistence context for an entry relating to this
                    // entity to be merged...
                    EntityEntry entry = source.PersistenceContext.GetEntry(entity);
                    if (entry == null)
                    {
                        IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);
                        object           id        = persister.GetIdentifier(entity);
                        if (id != null)
                        {
                            EntityKey key           = source.GenerateEntityKey(id, persister);
                            object    managedEntity = source.PersistenceContext.GetEntity(key);
                            entry = source.PersistenceContext.GetEntry(managedEntity);
                            if (entry != null)
                            {
                                // we have specialized case of a detached entity from the
                                // perspective of the merge operation.  Specifically, we
                                // have an incoming entity instance which has a corresponding
                                // entry in the current persistence context, but registered
                                // under a different entity instance
                                entityState = EntityState.Detached;
                            }
                        }
                    }

                    if (entityState == EntityState.Undefined)
                    {
                        entityState = await(GetEntityStateAsync(entity, @event.EntityName, entry, source, cancellationToken)).ConfigureAwait(false);
                    }

                    switch (entityState)
                    {
                    case EntityState.Persistent:
                        await(EntityIsPersistentAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Transient:
                        await(EntityIsTransientAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Detached:
                        await(EntityIsDetachedAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    default:
                        throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
                    }
                }
            }
        }
		/// <summary> Determine the id to use for updating. </summary>
		/// <param name="entity">The entity. </param>
		/// <param name="persister">The entity persister </param>
		/// <param name="requestedId">The requested identifier </param>
		/// <param name="entityMode">The entity mode. </param>
		/// <returns> The id. </returns>
		protected virtual object GetUpdateId(object entity, IEntityPersister persister, object requestedId, EntityMode entityMode)
		{
			// use the id assigned to the instance
			object id = persister.GetIdentifier(entity, entityMode);
			if (id == null)
			{
				// assume this is a newly instantiated transient object
				// which should be saved rather than updated
				throw new TransientObjectException("The given object has a null identifier: " + persister.EntityName);
			}
			else
			{
				return id;
			}
		}
Пример #35
0
		private static bool ExistsInDatabase(object entity, IEventSource source, IEntityPersister persister)
		{
			EntityEntry entry = source.PersistenceContext.GetEntry(entity);
			if (entry == null)
			{
				object id = persister.GetIdentifier(entity, source.EntityMode);
				if (id != null)
				{
					EntityKey key = new EntityKey(id, persister, source.EntityMode);
					object managedEntity = source.PersistenceContext.GetEntity(key);
					entry = source.PersistenceContext.GetEntry(managedEntity);
				}
			}

			if (entry == null)
			{
				// perhaps this should be an exception since it is only ever used
				// in the above method?
				return false;
			}
			else
			{
				return entry.ExistsInDatabase;
			}
		}