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)); }
/// <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); } }
/// <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); }
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); }
/// <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); } }
/// <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); } }
/// <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); } }
/// <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); } }
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); }
/// <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)); } }
/// <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); } }
/// <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)); } }
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); } }
/// <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); }
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)); }
/// <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); } }
/// <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); } } }
/// <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); } }
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); } }
/// <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); } }
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); }
/// <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); } }
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; } }
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; } }
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; } }