private void Set(IEntityPersister persister, object[] state, string propertyName, object value) { var index = Array.IndexOf(persister.PropertyNames, propertyName); if (index == -1) return; state[index] = value; }
/// <summary> /// Initializes a new instance of <see cref="ScheduledInsertion"/>. /// </summary> /// <param name="id">The identifier of the object.</param> /// <param name="state">An object array that contains the state of the object being inserted.</param> /// <param name="instance">The actual object instance.</param> /// <param name="version">The version of the object instance.</param> /// <param name="persister">The <see cref="IEntityPersister"/> that is responsible for the persisting the object.</param> /// <param name="session">The <see cref="ISessionImplementor"/> that the Action is occuring in.</param> public ScheduledInsertion(object id, object[] state, object instance, object version, IEntityPersister persister, ISessionImplementor session) : base(session, id, instance, persister) { this.state = state; this.version = version; }
private static IEnumerable<int> GetAdditionalDirtyProperties(IEntityPersister persister) { // Always update audit fields, even if their values don't change (dynamic-update=true would prevent this, hence this 'hack') var auditingInfoPropertyIndex = Array.IndexOf(persister.PropertyNames, "AuditingInfo"); if (auditingInfoPropertyIndex != -1) yield return auditingInfoPropertyIndex; }
/// <summary> /// Associates a given entity (either transient or associated with another session) to the given session. /// </summary> /// <param name="event">The event triggering the re-association </param> /// <param name="entity">The entity to be associated </param> /// <param name="id">The id of the entity. </param> /// <param name="persister">The entity's persister instance. </param> /// <returns> An EntityEntry representing the entity within this session. </returns> protected EntityEntry Reassociate(AbstractEvent @event, object entity, object id, IEntityPersister persister) { if (log.IsDebugEnabled) { log.Debug("Reassociating transient instance: " + MessageHelper.InfoString(persister, id, @event.Session.Factory)); } IEventSource source = @event.Session; EntityKey key = source.GenerateEntityKey(id, persister); source.PersistenceContext.CheckUniqueness(key, entity); //get a snapshot object[] values = persister.GetPropertyValues(entity, source.EntityMode); TypeHelper.DeepCopy(values, persister.PropertyTypes, persister.PropertyUpdateability, values, source); object version = Versioning.GetVersion(values, persister); EntityEntry newEntry = source.PersistenceContext.AddEntity( entity, persister.IsMutable ? Status.Loaded : Status.ReadOnly, values, key, version, LockMode.None, true, persister, false, true); new OnLockVisitor(source, id, entity).Process(entity, persister); persister.AfterReassociate(entity, source); return newEntry; }
public EntityDeleteAction(object id, object[] state, object version, object instance, IEntityPersister persister, bool isCascadeDeleteEnabled, ISessionImplementor session) : base(session, id, instance, persister) { this.state = state; this.version = version; this.isCascadeDeleteEnabled = isCascadeDeleteEnabled; }
public void Update(IAuditable auditable, object[] oldState, object[] state, IEntityPersister persister) { if (auditable == null) return; this.SetChange(auditable, state); }
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) { if (entity is IPermanent) { var e = (IPermanent)entity; e.IsDeleted = true; CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities); CascadeAfterDelete(session, persister, entity, transientEntities); } else { base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); } }
public DelWorkUnit(ISessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Object id, IEntityPersister entityPersister, Object[] state) : base(sessionImplementor, entityName, verCfg, id) { this.state = state; this.propertyNames = entityPersister.PropertyNames; }
protected override object PerformSave(object entity, object id, IEntityPersister persister, bool useIdentityColumn, object anything, IEventSource source, bool requiresImmediateIdAccess) { var entityValue = entity as EntityBase; if (entityValue != null) { if (entityValue.CreatedBy == null || entityValue.CreatedBy.Equals(string.Empty)) { entityValue.CreatedBy = EntityConstant.CreatedBy; entityValue.CreatedOn = DateTime.Now; } else { entityValue.UpdatedBy = EntityConstant.UpdatedBy; entityValue.UpdatedOn = DateTime.Now; } } foreach (var property in entity.GetType().GetProperties()) { var propertyValue = property.GetValue(entity, null); if (propertyValue == null) { continue; } if (propertyValue.GetType().IsSubclassOf(typeof(EntityBase))) { var value = propertyValue as EntityBase; value.CreatedBy = EntityConstant.CreatedBy; value.CreatedOn = DateTime.Now; } } return base.PerformSave(entityValue, id, persister, useIdentityColumn, anything, source, requiresImmediateIdAccess); }
/// <summary> /// Initializes a new instance of <see cref="ScheduledEntityAction"/>. /// </summary> /// <param name="session">The <see cref="ISessionImplementor"/> that the Action is occuring in.</param> /// <param name="id">The identifier of the object.</param> /// <param name="instance">The actual object instance.</param> /// <param name="persister">The <see cref="IEntityPersister"/> that is responsible for the persisting the object.</param> protected ScheduledEntityAction(ISessionImplementor session, object id, object instance, IEntityPersister persister) { this.session = session; this.id = id; this.persister = persister; this.instance = instance; }
/// <summary> Constructs an event containing the pertinent information. </summary> /// <param name="source">The session from which the event originated. </param> /// <param name="entity">The entity to be invloved in the database operation. </param> /// <param name="id">The entity id to be invloved in the database operation. </param> /// <param name="persister">The entity's persister. </param> protected AbstractPreDatabaseOperationEvent(IEventSource source, object entity, object id, IEntityPersister persister) : base(source) { Entity = entity; Id = id; Persister = persister; }
public BatchingEntityLoader(IEntityPersister persister, int[] batchSizes, Loader[] loaders) { this.batchSizes = batchSizes; this.loaders = loaders; this.persister = persister; idType = persister.IdentifierType; }
public PreDeleteEvent(object entity, object id, object[] deletedState, IEntityPersister persister) { this.entity = entity; this.id = id; this.deletedState = deletedState; this.persister = persister; }
private static string DetermineNameOfPropertyToUse(IEntityPersister persister, string supplied) { if (supplied != null) { return supplied; } int[] naturalIdPropertyIndices = persister.NaturalIdentifierProperties; if (naturalIdPropertyIndices == null) { throw new IdentifierGenerationException("no natural-id property defined; need to specify [key] in " + "generator parameters"); } if (naturalIdPropertyIndices.Length > 1) { throw new IdentifierGenerationException("select generator does not currently support composite " + "natural-id properties; need to specify [key] in generator parameters"); } ValueInclusion inclusion = persister.PropertyInsertGenerationInclusions[naturalIdPropertyIndices[0]]; if (inclusion != ValueInclusion.None) { throw new IdentifierGenerationException("natural-id also defined as insert-generated; need to specify [key] " + "in generator parameters"); } return persister.PropertyNames[naturalIdPropertyIndices[0]]; }
/// <summary> /// Generate small message that can be used in traces and exception messages. /// </summary> /// <param name="persister">The <see cref="IEntityPersister" /> for the class in question.</param> /// <param name="id">The identifier of the object.</param> /// <param name="factory">The <see cref="ISessionFactory" />.</param> /// <returns>A descriptive <see cref="String" /> in the format of <c>[classname#id]</c></returns> public static string InfoString(IEntityPersister persister, object id, ISessionFactoryImplementor factory) { StringBuilder s = new StringBuilder(); s.Append('['); if (persister == null) { s.Append("<null Class>"); } else { s.Append(persister.EntityName); } s.Append('#'); if (id == null) { s.Append("<null>"); } else { s.Append(id); } s.Append(']'); return s.ToString(); }
protected virtual void Validate(object entity, IEntityPersister persister, IEventSource source) { if (persister.ImplementsValidatable(source.EntityMode)) { ((IValidatable)entity).Validate(); } }
public EntityIdentityInsertAction(object[] state, object instance, IEntityPersister persister, ISessionImplementor session, bool isDelayed) : base(session, null, instance, persister) { this.state = state; this.isDelayed = isDelayed; delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : null; }
public void Update(IStampedEntity entity, object[] oldState, object[] state, IEntityPersister persister) { if (entity == null) return; SetChange(entity, state, persister); }
public AddWorkUnit(ISessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Object id, IEntityPersister entityPersister, Object[] state) : base(sessionImplementor, entityName, verCfg, id) { data = new Dictionary<String, Object>(); verCfg.EntCfg[EntityName].PropertyMapper.Map(sessionImplementor, data, entityPersister.PropertyNames, state, null); }
private void SetCreate(IStampedEntity entity, object[] state, IEntityPersister persister) { entity.CreatedBy = GetUserName(); SetState(persister, state, CREATED_BY, entity.CreatedBy); entity.CreatedTS = DateTime.Now; SetState(persister, state, CREATED_TS, entity.CreatedTS); }
public void Insert(IStampedEntity entity, object[] state, IEntityPersister persister) { if (entity == null) return; SetCreate(entity, state, persister); SetChange(entity, state, persister); }
public DelWorkUnit(ISessionImplementor sessionImplementor, string entityName, AuditConfiguration verCfg, object id, IEntityPersister entityPersister, object[] state) : base(sessionImplementor, entityName, verCfg, id, RevisionType.Deleted) { this.state = state; propertyNames = entityPersister.PropertyNames; this.entityPersister = entityPersister; }
private void CommitAuditInfo(IEntityPersister persister, object[] state, string propertyName) { var index = Array.IndexOf(persister.PropertyNames, propertyName); if (index == -1) return; state[index] = DateTime.UtcNow; }
public void Insert(IAuditable auditable, object[] state, IEntityPersister persister) { if (auditable == null) return; this.SetCreate(auditable, state); this.SetChange(auditable, state); }
public PostDeleteEvent(object entity, object id, object[] deletedState, IEntityPersister persister, IEventSource source) : base(source) { this.entity = entity; this.id = id; this.persister = persister; this.deletedState = deletedState; }
public PreInsertEvent(object entity, object id, object[] state, IEntityPersister persister, ISessionImplementor source) { this.entity = entity; this.id = id; this.state = state; this.persister = persister; this.source = source; }
public CacheEntry(object[] state, IEntityPersister persister, bool unfetched, object version, ISessionImplementor session, object owner) { //disassembled state gets put in a new array (we write to cache by value!) disassembledState = TypeFactory.Disassemble(state, persister.PropertyTypes, null, session, owner); subclass = persister.EntityName; lazyPropertiesAreUnfetched = unfetched || !persister.IsLazyPropertiesCacheable; this.version = version; }
private void SetState(IEntityPersister persister, object[] state, string propertyName, object value) { var index = GetIndex(persister, propertyName); if (index == -1) return; state[index] = value; }
public ModWorkUnit(ISessionImplementor sessionImplementor, String entityName, AuditConfiguration verCfg, Object id, IEntityPersister entityPersister, Object[] newState, Object[] oldState) : base(sessionImplementor, entityName, verCfg, id) { data = new Dictionary<String, Object>(); changes = verCfg.EntCfg[EntityName].PropertyMapper.Map(sessionImplementor, data, entityPersister.PropertyNames, newState, oldState); }
public PostInsertEvent(object entity, object id, object[] state, IEntityPersister persister, IEventSource source) : base(source) { this.entity = entity; this.id = id; this.state = state; this.persister = persister; }
protected virtual void PerformUpdate(SaveOrUpdateEvent @event, object entity, IEntityPersister persister) { if (!persister.IsMutable) { log.Debug("immutable instance passed to doUpdate(), locking"); Reassociate(@event, entity, @event.RequestedId, persister); } else { if (log.IsDebugEnabled) { log.Debug("updating " + MessageHelper.InfoString(persister, @event.RequestedId, @event.Session.Factory)); } IEventSource source = @event.Session; EntityKey key = new EntityKey(@event.RequestedId, persister, source.EntityMode); source.PersistenceContext.CheckUniqueness(key, entity); if (InvokeUpdateLifecycle(entity, persister, source)) { Reassociate(@event, @event.Entity, @event.RequestedId, persister); return; } // this is a transient object with existing persistent state not loaded by the session new OnUpdateVisitor(source, @event.RequestedId, entity).Process(entity, persister); //TODO: put this stuff back in to read snapshot from // the second-level cache (needs some extra work) /*Object[] cachedState = null; * * if ( persister.hasCache() ) { * CacheEntry entry = (CacheEntry) persister.getCache() * .get( event.getRequestedId(), source.getTimestamp() ); * cachedState = entry==null ? * null : * entry.getState(); //TODO: half-assemble this stuff * }*/ source.PersistenceContext.AddEntity(entity, Status.Loaded, null, key, persister.GetVersion(entity, source.EntityMode), LockMode.None, true, persister, false, true); //persister.AfterReassociate(entity, source); TODO H3.2 not ported if (log.IsDebugEnabled) { log.Debug("updating " + MessageHelper.InfoString(persister, @event.RequestedId, source.Factory)); } CascadeOnUpdate(@event, persister, entity); } }
private bool IsVersionIncrementRequired(FlushEntityEvent @event, EntityEntry entry, IEntityPersister persister, int[] dirtyProperties) { // NH different behavior: because NH-1756 when PostInsertId is used with a generated version // the version is read inmediately after save and does not need to be incremented. // BTW, in general, a generated version does not need to be incremented by NH. bool isVersionIncrementRequired = entry.Status != Status.Deleted && !persister.IsVersionPropertyGenerated && (dirtyProperties == null || Versioning.IsVersionIncrementRequired(dirtyProperties, @event.HasDirtyCollection, persister.PropertyVersionability)); return(isVersionIncrementRequired); }
private bool IsCollectionDirtyCheckNecessary(IEntityPersister persister, Status status) { return((status == Status.Loaded || status == Status.ReadOnly) && persister.IsVersioned && persister.HasCollections); }
public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners) { Init(); log.Info("building session factory"); properties = new Dictionary <string, string>(cfg.Properties); interceptor = cfg.Interceptor; this.settings = settings; sqlFunctionRegistry = new SQLFunctionRegistry(settings.Dialect, cfg.SqlFunctions); eventListeners = listeners; filters = new Dictionary <string, FilterDefinition>(cfg.FilterDefinitions); if (log.IsDebugEnabled) { log.Debug("Session factory constructed with filter configurations : " + CollectionPrinter.ToString(filters)); } if (log.IsDebugEnabled) { log.Debug("instantiating session factory with properties: " + CollectionPrinter.ToString(properties)); } try { if (settings.IsKeywordsImportEnabled) { SchemaMetadataUpdater.Update(this); } if (settings.IsAutoQuoteEnabled) { SchemaMetadataUpdater.QuoteTableAndColumns(cfg); } } catch (NotSupportedException) { // Ignore if the Dialect does not provide DataBaseSchema } #region Caches settings.CacheProvider.Start(properties); #endregion #region Generators identifierGenerators = new Dictionary <string, IIdentifierGenerator>(); foreach (PersistentClass model in cfg.ClassMappings) { if (!model.IsInherited) { IIdentifierGenerator generator = model.Identifier.CreateIdentifierGenerator(settings.Dialect, settings.DefaultCatalogName, settings.DefaultSchemaName, (RootClass)model); identifierGenerators[model.EntityName] = generator; } } #endregion #region Persisters Dictionary <string, ICacheConcurrencyStrategy> caches = new Dictionary <string, ICacheConcurrencyStrategy>(); entityPersisters = new Dictionary <string, IEntityPersister>(); implementorToEntityName = new Dictionary <System.Type, string>(); Dictionary <string, IClassMetadata> classMeta = new Dictionary <string, IClassMetadata>(); foreach (PersistentClass model in cfg.ClassMappings) { model.PrepareTemporaryTables(mapping, settings.Dialect); string cacheRegion = model.RootClazz.CacheRegionName; ICacheConcurrencyStrategy cache; if (!caches.TryGetValue(cacheRegion, out cache)) { cache = CacheFactory.CreateCache(model.CacheConcurrencyStrategy, cacheRegion, model.IsMutable, settings, properties); if (cache != null) { caches.Add(cacheRegion, cache); if (!allCacheRegions.TryAdd(cache.RegionName, cache.Cache)) { throw new HibernateException("An item with the same key has already been added to allCacheRegions."); } } } IEntityPersister cp = PersisterFactory.CreateClassPersister(model, cache, this, mapping); entityPersisters[model.EntityName] = cp; classMeta[model.EntityName] = cp.ClassMetadata; if (model.HasPocoRepresentation) { implementorToEntityName[model.MappedClass] = model.EntityName; } } classMetadata = new UnmodifiableDictionary <string, IClassMetadata>(classMeta); Dictionary <string, ISet <string> > tmpEntityToCollectionRoleMap = new Dictionary <string, ISet <string> >(); collectionPersisters = new Dictionary <string, ICollectionPersister>(); foreach (Mapping.Collection model in cfg.CollectionMappings) { ICacheConcurrencyStrategy cache = CacheFactory.CreateCache(model.CacheConcurrencyStrategy, model.CacheRegionName, model.Owner.IsMutable, settings, properties); if (cache != null) { allCacheRegions[cache.RegionName] = cache.Cache; } ICollectionPersister persister = PersisterFactory.CreateCollectionPersister(model, cache, this); collectionPersisters[model.Role] = persister; IType indexType = persister.IndexType; if (indexType != null && indexType.IsAssociationType && !indexType.IsAnyType) { string entityName = ((IAssociationType)indexType).GetAssociatedEntityName(this); ISet <string> roles; if (!tmpEntityToCollectionRoleMap.TryGetValue(entityName, out roles)) { roles = new HashSet <string>(); tmpEntityToCollectionRoleMap[entityName] = roles; } roles.Add(persister.Role); } IType elementType = persister.ElementType; if (elementType.IsAssociationType && !elementType.IsAnyType) { string entityName = ((IAssociationType)elementType).GetAssociatedEntityName(this); ISet <string> roles; if (!tmpEntityToCollectionRoleMap.TryGetValue(entityName, out roles)) { roles = new HashSet <string>(); tmpEntityToCollectionRoleMap[entityName] = roles; } roles.Add(persister.Role); } } Dictionary <string, ICollectionMetadata> tmpcollectionMetadata = new Dictionary <string, ICollectionMetadata>(collectionPersisters.Count); foreach (KeyValuePair <string, ICollectionPersister> collectionPersister in collectionPersisters) { tmpcollectionMetadata.Add(collectionPersister.Key, collectionPersister.Value.CollectionMetadata); } collectionMetadata = new UnmodifiableDictionary <string, ICollectionMetadata>(tmpcollectionMetadata); collectionRolesByEntityParticipant = new UnmodifiableDictionary <string, ISet <string> >(tmpEntityToCollectionRoleMap); #endregion #region Named Queries namedQueries = new Dictionary <string, NamedQueryDefinition>(cfg.NamedQueries); namedSqlQueries = new Dictionary <string, NamedSQLQueryDefinition>(cfg.NamedSQLQueries); sqlResultSetMappings = new Dictionary <string, ResultSetMappingDefinition>(cfg.SqlResultSetMappings); #endregion imports = new Dictionary <string, string>(cfg.Imports); #region after *all* persisters and named queries are registered foreach (IEntityPersister persister in entityPersisters.Values) { persister.PostInstantiate(); } foreach (ICollectionPersister persister in collectionPersisters.Values) { persister.PostInstantiate(); } #endregion #region Serialization info name = settings.SessionFactoryName; try { uuid = (string)UuidGenerator.Generate(null, null); } catch (Exception) { throw new AssertionFailure("Could not generate UUID"); } SessionFactoryObjectFactory.AddInstance(uuid, name, this, properties); #endregion log.Debug("Instantiated session factory"); #region Schema management if (settings.IsAutoCreateSchema) { new SchemaExport(cfg).Create(false, true); } if (settings.IsAutoUpdateSchema) { new SchemaUpdate(cfg).Execute(false, true); } if (settings.IsAutoValidateSchema) { new SchemaValidator(cfg, settings).Validate(); } if (settings.IsAutoDropSchema) { schemaExport = new SchemaExport(cfg); } #endregion #region Obtaining TransactionManager // not ported yet #endregion currentSessionContext = BuildCurrentSessionContext(); if (settings.IsQueryCacheEnabled) { updateTimestampsCache = new UpdateTimestampsCache(settings, properties); queryCache = settings.QueryCacheFactory.GetQueryCache(null, updateTimestampsCache, settings, properties); queryCaches = new ConcurrentDictionary <string, IQueryCache>(); } else { updateTimestampsCache = null; queryCache = null; queryCaches = null; } #region Checking for named queries if (settings.IsNamedQueryStartupCheckingEnabled) { IDictionary <string, HibernateException> errors = CheckNamedQueries(); if (errors.Count > 0) { StringBuilder failingQueries = new StringBuilder("Errors in named queries: "); foreach (KeyValuePair <string, HibernateException> pair in errors) { failingQueries.Append('{').Append(pair.Key).Append('}'); log.Error("Error in named query: " + pair.Key, pair.Value); } throw new HibernateException(failingQueries.ToString()); } } #endregion Statistics.IsStatisticsEnabled = settings.IsStatisticsEnabled; // EntityNotFoundDelegate IEntityNotFoundDelegate enfd = cfg.EntityNotFoundDelegate; if (enfd == null) { enfd = new DefaultEntityNotFoundDelegate(); } entityNotFoundDelegate = enfd; }
protected virtual bool InvokeDeleteLifecycle(IEventSource session, object entity, IEntityPersister persister) { if (persister.ImplementsLifecycle(session.EntityMode)) { log.Debug("calling onDelete()"); if (((ILifecycle)entity).OnDelete(session) == LifecycleVeto.Veto) { log.Debug("deletion vetoed by onDelete()"); return(true); } } return(false); }
/// <summary> Perform a dirty check, and attach the results to the event</summary> protected virtual async Task DirtyCheckAsync(FlushEntityEvent @event, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); object entity = @event.Entity; object[] values = @event.PropertyValues; ISessionImplementor session = @event.Session; EntityEntry entry = @event.EntityEntry; IEntityPersister persister = entry.Persister; object id = entry.Id; object[] loadedState = entry.LoadedState; int[] dirtyProperties = session.Interceptor.FindDirty(entity, id, values, loadedState, persister.PropertyNames, persister.PropertyTypes); @event.DatabaseSnapshot = null; bool interceptorHandledDirtyCheck; bool cannotDirtyCheck; if (dirtyProperties == null) { // Interceptor returned null, so do the dirtycheck ourself, if possible interceptorHandledDirtyCheck = false; cannotDirtyCheck = loadedState == null; // object loaded by update() if (!cannotDirtyCheck) { // dirty check against the usual snapshot of the entity dirtyProperties = await(persister.FindDirtyAsync(values, loadedState, entity, session, cancellationToken)).ConfigureAwait(false); } else if (entry.Status == Status.Deleted && [email protected]()) { // A non-modifiable (e.g., read-only or immutable) entity needs to be have // references to transient entities set to null before being deleted. No other // fields should be updated. if (values != entry.DeletedState) { throw new InvalidOperationException("Entity has status Status.Deleted but values != entry.DeletedState"); } // Even if loadedState == null, we can dirty-check by comparing currentState and // entry.getDeletedState() because the only fields to be updated are those that // refer to transient entities that are being set to null. // - currentState contains the entity's current property values. // - entry.getDeletedState() contains the entity's current property values with // references to transient entities set to null. // - dirtyProperties will only contain properties that refer to transient entities object[] currentState = persister.GetPropertyValues(@event.Entity); dirtyProperties = await(persister.FindDirtyAsync(entry.DeletedState, currentState, entity, session, cancellationToken)).ConfigureAwait(false); cannotDirtyCheck = false; } else { // dirty check against the database snapshot, if possible/necessary object[] databaseSnapshot = await(GetDatabaseSnapshotAsync(session, persister, id, cancellationToken)).ConfigureAwait(false); if (databaseSnapshot != null) { dirtyProperties = await(persister.FindModifiedAsync(databaseSnapshot, values, entity, session, cancellationToken)).ConfigureAwait(false); cannotDirtyCheck = false; @event.DatabaseSnapshot = databaseSnapshot; } } } else { // the Interceptor handled the dirty checking cannotDirtyCheck = false; interceptorHandledDirtyCheck = true; } @event.DirtyProperties = dirtyProperties; @event.DirtyCheckHandledByInterceptor = interceptorHandledDirtyCheck; @event.DirtyCheckPossible = !cannotDirtyCheck; }
private async Task <bool> ScheduleUpdateAsync(FlushEntityEvent @event, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); EntityEntry entry = @event.EntityEntry; IEventSource session = @event.Session; object entity = @event.Entity; Status status = entry.Status; IEntityPersister persister = entry.Persister; object[] values = @event.PropertyValues; if (log.IsDebugEnabled()) { if (status == Status.Deleted) { if (!persister.IsMutable) { log.Debug("Updating immutable, deleted entity: {0}", MessageHelper.InfoString(persister, entry.Id, session.Factory)); } else if (!entry.IsModifiableEntity()) { log.Debug("Updating non-modifiable, deleted entity: {0}", MessageHelper.InfoString(persister, entry.Id, session.Factory)); } else { log.Debug("Updating deleted entity: {0}", MessageHelper.InfoString(persister, entry.Id, session.Factory)); } } else { log.Debug("Updating entity: {0}", MessageHelper.InfoString(persister, entry.Id, session.Factory)); } } bool intercepted; if (!entry.IsBeingReplicated) { // give the Interceptor a chance to process property values, if the properties // were modified by the Interceptor, we need to set them back to the object intercepted = await(HandleInterceptionAsync(@event, cancellationToken)).ConfigureAwait(false); } else { intercepted = false; } Validate(entity, persister, status); // increment the version number (if necessary) object nextVersion = await(GetNextVersionAsync(@event, cancellationToken)).ConfigureAwait(false); // if it was dirtied by a collection only int[] dirtyProperties = @event.DirtyProperties; if (@event.DirtyCheckPossible && dirtyProperties == null) { if (!intercepted && [email protected]) { throw new AssertionFailure("dirty, but no dirty properties"); } dirtyProperties = Array.Empty <int>(); } // check nullability but do not perform command execute // we'll use scheduled updates for that. new Nullability(session).CheckNullability(values, persister, true); // schedule the update // note that we intentionally do _not_ pass in currentPersistentState! session.ActionQueue.AddAction( new EntityUpdateAction( entry.Id, values, dirtyProperties, @event.HasDirtyCollection, status == Status.Deleted && !entry.IsModifiableEntity() ? persister.GetPropertyValues(entity) : entry.LoadedState, entry.Version, nextVersion, entity, persister, session)); return(intercepted); }
/// <summary> /// Add an uninitialized instance of an entity class, as a placeholder to ensure object /// identity. Must be called before <tt>postHydrate()</tt>. /// Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized, /// but we need the mapping from id to instance in order to guarantee uniqueness. /// </summary> public static void AddUninitializedEntity(EntityKey key, object obj, IEntityPersister persister, LockMode lockMode, ISessionImplementor session) { session.PersistenceContext.AddEntity(obj, Status.Loading, null, key, null, lockMode, true, persister, false); }
/// <summary> /// We encountered a delete request on a transient instance. /// <p/> /// This is a deviation from historical Hibernate (pre-3.2) behavior to /// align with the JPA spec, which states that transient entities can be /// passed to remove operation in which case cascades still need to be /// performed. /// </summary> /// <param name="session">The session which is the source of the event </param> /// <param name="entity">The entity being delete processed </param> /// <param name="cascadeDeleteEnabled">Is cascading of deletes enabled</param> /// <param name="persister">The entity persister </param> /// <param name="transientEntities"> /// A cache of already visited transient entities (to avoid infinite recursion). /// </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> protected virtual async Task DeleteTransientEntityAsync(IEventSource session, object entity, bool cascadeDeleteEnabled, IEntityPersister persister, ISet <object> transientEntities, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); log.Info("handling transient entity in delete processing"); // NH different impl : NH-1895 if (transientEntities == null) { transientEntities = new HashSet <object>(); } if (!transientEntities.Add(entity)) { log.Debug("already handled transient entity; skipping"); return; } await(CascadeBeforeDeleteAsync(session, persister, entity, null, transientEntities, cancellationToken)).ConfigureAwait(false); await(CascadeAfterDeleteAsync(session, persister, entity, transientEntities, cancellationToken)).ConfigureAwait(false); }
/// <summary> /// Perform the entity deletion. Well, as with most operations, does not /// really perform it; just schedules an action/execution with the /// <see cref="ActionQueue"/> for execution during flush. /// </summary> /// <param name="session">The originating session </param> /// <param name="entity">The entity to delete </param> /// <param name="entityEntry">The entity's entry in the <see cref="ISession"/> </param> /// <param name="isCascadeDeleteEnabled">Is delete cascading enabled? </param> /// <param name="persister">The entity persister. </param> /// <param name="transientEntities">A cache of already deleted entities. </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> protected virtual async Task DeleteEntityAsync(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet <object> transientEntities, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (log.IsDebugEnabled) { log.Debug("deleting " + MessageHelper.InfoString(persister, entityEntry.Id, session.Factory)); } IPersistenceContext persistenceContext = session.PersistenceContext; IType[] propTypes = persister.PropertyTypes; object version = entityEntry.Version; object[] currentState; if (entityEntry.LoadedState == null) { //ie. the entity came in from update() currentState = persister.GetPropertyValues(entity); } else { currentState = entityEntry.LoadedState; } object[] deletedState = CreateDeletedState(persister, currentState, session); entityEntry.DeletedState = deletedState; session.Interceptor.OnDelete(entity, entityEntry.Id, deletedState, persister.PropertyNames, propTypes); // before any callbacks, etc, so subdeletions see that this deletion happened first persistenceContext.SetEntryStatus(entityEntry, Status.Deleted); EntityKey key = session.GenerateEntityKey(entityEntry.Id, persister); await(CascadeBeforeDeleteAsync(session, persister, entity, entityEntry, transientEntities, cancellationToken)).ConfigureAwait(false); await(new ForeignKeys.Nullifier(entity, true, false, session).NullifyTransientReferencesAsync(entityEntry.DeletedState, propTypes, cancellationToken)).ConfigureAwait(false); new Nullability(session).CheckNullability(entityEntry.DeletedState, persister, true); persistenceContext.NullifiableEntityKeys.Add(key); // Ensures that containing deletions happen before sub-deletions session.ActionQueue.AddAction(new EntityDeleteAction(entityEntry.Id, deletedState, version, entity, persister, isCascadeDeleteEnabled, session)); await(CascadeAfterDeleteAsync(session, persister, entity, transientEntities, cancellationToken)).ConfigureAwait(false); // the entry will be removed after the flush, and will no longer // override the stale snapshot // This is now handled by removeEntity() in EntityDeleteAction //persistenceContext.removeDatabaseSnapshot(key); }
public void SetUp() { sessionFactory = SessionFactoryHelper.Build(); persisterForTestSaga = sessionFactory.GetEntityPersisterFor <TestSaga>(); }
public EntityKey GenerateEntityKey(object id, IEntityPersister persister) { return(new EntityKey(id, persister)); }
/// <summary> Cascade an action from the parent entity instance to all its children. </summary> /// <param name="persister">The parent's entity persister </param> /// <param name="parent">The parent reference. </param> public void CascadeOn(IEntityPersister persister, object parent) { CascadeOn(persister, parent, null); }
private async Task <object[]> GetDatabaseSnapshotAsync(ISessionImplementor session, IEntityPersister persister, object id, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (persister.IsSelectBeforeUpdateRequired) { object[] snapshot = await(session.PersistenceContext.GetDatabaseSnapshotAsync(id, persister, cancellationToken)).ConfigureAwait(false); if (snapshot == null) { //do we even really need this? the update will fail anyway.... if (session.Factory.Statistics.IsStatisticsEnabled) { session.Factory.StatisticsImplementor.OptimisticFailure(persister.EntityName); } throw new StaleObjectStateException(persister.EntityName, id); } else { return(snapshot); } } else { //TODO: optimize away this lookup for entities w/o unsaved-value="undefined" EntityKey entityKey = session.GenerateEntityKey(id, persister); return(session.PersistenceContext.GetCachedDatabaseSnapshot(entityKey)); } }
/// <summary> /// We encountered a delete request on a transient instance. /// <p/> /// This is a deviation from historical Hibernate (pre-3.2) behavior to /// align with the JPA spec, which states that transient entities can be /// passed to remove operation in which case cascades still need to be /// performed. /// </summary> /// <param name="session">The session which is the source of the event </param> /// <param name="entity">The entity being delete processed </param> /// <param name="cascadeDeleteEnabled">Is cascading of deletes enabled</param> /// <param name="persister">The entity persister </param> /// <param name="transientEntities"> /// A cache of already visited transient entities (to avoid infinite recursion). /// </param> protected virtual void DeleteTransientEntity(IEventSource session, object entity, bool cascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) { log.Info("handling transient entity in delete processing"); // NH different impl : NH-1895 if (transientEntities == null) { transientEntities = new HashedSet(); } if (!transientEntities.Add(entity)) { log.Debug("already handled transient entity; skipping"); return; } CascadeBeforeDelete(session, persister, entity, null, transientEntities); CascadeAfterDelete(session, persister, entity, transientEntities); }
public override void Execute() { IEntityPersister persister = Persister; ISessionImplementor session = Session; object instance = Instance; object id = Id; bool statsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; Stopwatch stopwatch = null; if (statsEnabled) { stopwatch = Stopwatch.StartNew(); } bool veto = PreInsert(); // Don't need to lock the cache here, since if someone // else inserted the same pk first, the insert would fail if (!veto) { persister.Insert(id, state, instance, Session); EntityEntry entry = Session.PersistenceContext.GetEntry(instance); if (entry == null) { throw new AssertionFailure("Possible nonthreadsafe access to session"); } entry.PostInsert(); if (persister.HasInsertGeneratedProperties) { persister.ProcessInsertGeneratedProperties(id, instance, state, Session); if (persister.IsVersionPropertyGenerated) { version = Versioning.GetVersion(state, persister); } entry.PostUpdate(instance, state, version); } } ISessionFactoryImplementor factory = Session.Factory; if (IsCachePutEnabled(persister)) { CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance); cacheEntry = persister.CacheEntryStructure.Structure(ce); CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); bool put = persister.Cache.Insert(ck, cacheEntry, version); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); } } PostInsert(); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.InsertEntity(Persister.EntityName, stopwatch.Elapsed); } }
protected virtual void EntityIsDetached(MergeEvent @event, IDictionary copyCache) { 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, source.EntityMode); } else { // check that entity id = requestedId object entityId = persister.GetIdentifier(entity, source.EntityMode); if (!persister.IdentifierType.IsEqual(id, entityId, source.EntityMode, 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.EntityMode, source.Factory); object result = source.Get(persister.EntityName, clonedIdentifier); 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 EntityIsTransient(@event, copyCache); } else { // NH different behavior : NH-1517 if (InvokeUpdateLifecycle(entity, persister, source)) { return; } copyCache[entity] = result; //before cascade! object target = source.PersistenceContext.Unproxy(result); if (target == entity) { throw new AssertionFailure("entity was not detached"); } else if (!source.GetEntityName(target).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 CascadeOnMerge(source, persister, entity, copyCache); CopyValues(persister, entity, target, source, copyCache); //copyValues works by reflection, so explicitly mark the entity instance dirty MarkInterceptorDirty(entity, target); @event.Result = result; } }
private int GetIndex(IEntityPersister persister, string propertyName) { return(Array.IndexOf(persister.PropertyNames, propertyName)); }
/// <summary> /// Get the version number of the given instance state snapshot /// </summary> /// <param name="fields">An array of objects that contains a snapshot of a persistent object.</param> /// <param name="persister">The <see cref="IEntityPersister"/> that is responsible for persisting the values of the <c>fields</c> parameter.</param> /// <returns> /// The value of the version contained in the <c>fields</c> parameter or null if the /// Entity is not versioned. /// </returns> public static object GetVersion(object[] fields, IEntityPersister persister) { return(persister.IsVersioned ? fields[persister.VersionProperty] : null); }
/// <summary> Cascade behavior is redefined by this subclass, disable superclass behavior</summary> protected override void CascadeBeforeSave(IEventSource source, IEntityPersister persister, object entity, object anything) { }
public EntityInsertAction(object id, object[] state, object instance, object version, IEntityPersister persister, ISessionImplementor session) : base(session, id, instance, persister) { this.state = state; this.version = version; }
public virtual void OnMerge(MergeEvent @event, IDictionary copyCache) { IEventSource source = @event.Session; object original = @event.Original; if (original != null) { object entity; if (original is INHibernateProxy) { ILazyInitializer li = ((INHibernateProxy)original).HibernateLazyInitializer; if (li.IsUninitialized) { log.Debug("ignoring uninitialized proxy"); @event.Result = source.Load(li.PersistentClass, li.Identifier); return; //EARLY EXIT! } else { entity = li.GetImplementation(); } } else { entity = original; } if (copyCache.Contains(entity)) { log.Debug("already merged"); @event.Result = entity; } else { @event.Entity = entity; EntityState entityState = EntityState.Undefined; // 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, 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) { // 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 = GetEntityState(entity, @event.EntityName, entry, source); } switch (entityState) { case EntityState.Persistent: EntityIsPersistent(@event, copyCache); break; case EntityState.Transient: EntityIsTransient(@event, copyCache); break; case EntityState.Detached: EntityIsDetached(@event, copyCache); break; default: throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity)); } } } }
private bool IsCachePutEnabled(IEntityPersister persister) { return (persister.HasCache && !persister.IsCacheInvalidationRequired && ((Session.CacheMode & CacheMode.Put) == CacheMode.Put)); }
private void DereferenceCollection(CollectionType collectionType, bool implicitJoin, bool indexed, string classAlias) { _dereferenceType = DerefCollection; string role = collectionType.Role; //foo.bars.size (also handles deprecated stuff like foo.bars.maxelement for backwardness) IASTNode sibling = NextSibling; bool isSizeProperty = sibling != null && CollectionProperties.IsAnyCollectionProperty(sibling.Text); if (isSizeProperty) { indexed = true; //yuck!} } IQueryableCollection queryableCollection = SessionFactoryHelper.RequireQueryableCollection(role); string propName = Path; FromClause currentFromClause = Walker.CurrentFromClause; if (Walker.StatementType != HqlSqlWalker.SELECT && indexed && classAlias == null) { // should indicate that we are processing an INSERT/UPDATE/DELETE // query with a subquery implied via a collection property // function. Here, we need to use the table name itself as the // qualification alias. // TODO : verify this works for all databases... // TODO : is this also the case in non-"indexed" scenarios? string alias = GetLhs().FromElement.Queryable.TableName; _columns = FromElement.ToColumns(alias, _propertyPath, false, true); } //We do not look for an existing join on the same path, because //it makes sense to join twice on the same collection role var factory = new FromElementFactory( currentFromClause, GetLhs().FromElement, propName, classAlias, GetColumns(), implicitJoin ); FromElement elem = factory.CreateCollection(queryableCollection, role, _joinType, _fetch, indexed); if (Log.IsDebugEnabled()) { Log.Debug("dereferenceCollection() : Created new FROM element for {0} : {1}", propName, elem); } SetImpliedJoin(elem); FromElement = elem; // This 'dot' expression now refers to the resulting from element. if (isSizeProperty) { elem.Text = ""; elem.UseWhereFragment = false; } if (!implicitJoin) { IEntityPersister entityPersister = elem.EntityPersister; if (entityPersister != null) { Walker.AddQuerySpaces(entityPersister.QuerySpaces); } } Walker.AddQuerySpaces(queryableCollection.CollectionSpaces); // Always add the collection's query spaces. }
/// <summary> /// Associates a given entity (either transient or associated with another session) to the given session. /// </summary> /// <param name="event">The event triggering the re-association </param> /// <param name="entity">The entity to be associated </param> /// <param name="id">The id of the entity. </param> /// <param name="persister">The entity's persister instance. </param> /// <returns> An EntityEntry representing the entity within this session. </returns> protected EntityEntry Reassociate(AbstractEvent @event, object entity, object id, IEntityPersister persister) { if (log.IsDebugEnabled) { log.Debug("Reassociating transient instance: " + MessageHelper.InfoString(persister, id, @event.Session.Factory)); } IEventSource source = @event.Session; EntityKey key = new EntityKey(id, persister, source.EntityMode); source.PersistenceContext.CheckUniqueness(key, entity); //get a snapshot object[] values = persister.GetPropertyValues(entity, source.EntityMode); TypeFactory.DeepCopy(values, persister.PropertyTypes, persister.PropertyUpdateability, values, source); object version = Versioning.GetVersion(values, persister); EntityEntry newEntry = source.PersistenceContext.AddEntity(entity, Status.Loaded, values, key, version, LockMode.None, true, persister, false, true); new OnLockVisitor(source, id, entity).Process(entity, persister); persister.AfterReassociate(entity, source); return(newEntry); }
/// <summary> /// Recursive Helper for <see cref="IsReferencedByCompositeId(IEntityPersister)"/>. /// </summary> /// <param name="rootEM"></param> /// <param name="nestedEM"></param> /// <param name="neestedIsCompositeId"></param> /// <param name="visitedList"></param> /// <returns></returns> private EntityMetamodel GetReferrerByCompositeId( EntityMetamodel rootEM, EntityMetamodel nestedEM, bool neestedIsCompositeId, ICollection <EntityMetamodel> visitedList) { EntityMetamodel emResult = null; if (visitedList.Contains(nestedEM)) { return(emResult); } else { visitedList.Add(nestedEM); ISessionFactoryImplementor sessionImplementor = rootEM.SessionFactory; if (nestedEM.IdentifierProperty.Type is IAbstractComponentType) { IAbstractComponentType componentType = (IAbstractComponentType)nestedEM.IdentifierProperty.Type; for (int i = 0; i < componentType.Subtypes.Length; i++) { IType subType = componentType.Subtypes[i]; if (!subType.IsAnyType && subType.IsAssociationType && subType is IAssociationType) { IAssociationType associationType = (IAssociationType)subType; string associatedEntityName = null; try { //for 'Collection Types', sometimes 'Element Type' is not an 'Entity Type' associatedEntityName = associationType.GetAssociatedEntityName(sessionImplementor); } catch (MappingException me) { //I think it will never happen because a //"Composit Id" can not have a property that //uses 'NHibernate.Type.CollectionType'. //But just in case ... if (log.IsDebugEnabled) { log.Debug("Can not perform 'GetAssociatedEntityName'. " + "Considering it is not an entity type: '" + nestedEM.IdentifierProperty.Name + "." + componentType.PropertyNames[i] + "'" , me); } } if (associatedEntityName != null) { IEntityPersister persisterNextNested = sessionImplementor.GetEntityPersister(associatedEntityName); if (rootEM == persisterNextNested.EntityMetamodel) { emResult = nestedEM; return(emResult); } else { emResult = this.GetReferrerByCompositeId( rootEM, persisterNextNested.EntityMetamodel, true, visitedList); if (emResult != null) { return(emResult); } } } } } } for (int i = 0; i < nestedEM.Properties.Length; i++) { StandardProperty property = nestedEM.Properties[i]; if (!property.Type.IsAnyType && property.Type.IsAssociationType && property.Type is IAssociationType) { IAssociationType associationType = (IAssociationType)property.Type; string associatedEntityName = null; try { //for 'Collection Types', sometimes 'Element Type' is not an 'Entity Type' associatedEntityName = associationType.GetAssociatedEntityName(sessionImplementor); } catch (MappingException me) { if (log.IsDebugEnabled) { log.Debug("Can not perform 'GetAssociatedEntityName'. " + "Considering it is not an entity type: '" + nestedEM.EntityType.Name + "." + nestedEM.PropertyNames[i] + "'", me); } } if (associatedEntityName != null) { IEntityPersister persisterNextNested = sessionImplementor.GetEntityPersister(associatedEntityName); emResult = this.GetReferrerByCompositeId( rootEM, persisterNextNested.EntityMetamodel, false, visitedList); if (emResult != null) { return(emResult); } } } } } return(null); }
// Evict collections from the factory-level cache private void EvictCachedCollections(IEntityPersister persister, object id, ISessionFactoryImplementor factory) { EvictCachedCollections(persister.PropertyTypes, id, factory); }
public NamedQueryLoader(string queryName, IEntityPersister persister) { this.queryName = queryName; this.persister = persister; }
/// <summary> /// Perform the second step of 2-phase load. Fully initialize the entity instance. /// After processing a JDBC result set, we "resolve" all the associations /// between the entities which were instantiated and had their state /// "hydrated" into an array /// </summary> internal static void InitializeEntity(object entity, bool readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent, Action <IEntityPersister, CachePutData> cacheBatchingHandler) { //TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!) Stopwatch stopWatch = null; if (session.Factory.Statistics.IsStatisticsEnabled) { stopWatch = Stopwatch.StartNew(); } IPersistenceContext persistenceContext = session.PersistenceContext; EntityEntry entityEntry = persistenceContext.GetEntry(entity); if (entityEntry == null) { throw new AssertionFailure("possible non-threadsafe access to the session"); } IEntityPersister persister = entityEntry.Persister; object id = entityEntry.Id; object[] hydratedState = entityEntry.LoadedState; if (log.IsDebugEnabled()) { log.Debug("resolving associations for {0}", MessageHelper.InfoString(persister, id, session.Factory)); } IType[] types = persister.PropertyTypes; var collectionToResolveIndexes = new List <int>(hydratedState.Length); for (int i = 0; i < hydratedState.Length; i++) { object value = hydratedState[i]; if (!Equals(LazyPropertyInitializer.UnfetchedProperty, value) && !(Equals(BackrefPropertyAccessor.Unknown, value))) { if (types[i].IsCollectionType) { // Resolve them last, because they may depend on other properties if they use a property-ref collectionToResolveIndexes.Add(i); continue; } hydratedState[i] = CustomEntityTypeMapper.Map(types[i]).ResolveIdentifier(value, session, entity); } } foreach (var i in collectionToResolveIndexes) { hydratedState[i] = CustomEntityTypeMapper.Map(types[i]).ResolveIdentifier(hydratedState[i], session, entity); } //Must occur after resolving identifiers! if (session.IsEventSource) { preLoadEvent.Entity = entity; preLoadEvent.State = hydratedState; preLoadEvent.Id = id; preLoadEvent.Persister = persister; IPreLoadEventListener[] listeners = session.Listeners.PreLoadEventListeners; for (int i = 0; i < listeners.Length; i++) { listeners[i].OnPreLoad(preLoadEvent); } } persister.SetPropertyValues(entity, hydratedState); ISessionFactoryImplementor factory = session.Factory; if (persister.HasCache && session.CacheMode.HasFlag(CacheMode.Put)) { if (log.IsDebugEnabled()) { log.Debug("adding entity to second-level cache: {0}", MessageHelper.InfoString(persister, id, session.Factory)); } object version = Versioning.GetVersion(hydratedState, persister); CacheEntry entry = CacheEntry.Create(hydratedState, persister, version, session, entity); CacheKey cacheKey = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); if (cacheBatchingHandler != null && persister.IsBatchLoadable) { cacheBatchingHandler( persister, new CachePutData( cacheKey, persister.CacheEntryStructure.Structure(entry), version, persister.IsVersioned ? persister.VersionType.Comparator : null, UseMinimalPuts(session, entityEntry))); } else { bool put = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, persister.IsVersioned ? persister.VersionType.Comparator : null, UseMinimalPuts(session, entityEntry)); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(persister.Cache.RegionName); } } } bool isReallyReadOnly = readOnly; if (!persister.IsMutable) { isReallyReadOnly = true; } else { object proxy = persistenceContext.GetProxy(entityEntry.EntityKey); if (proxy != null) { // there is already a proxy for this impl // only set the status to read-only if the proxy is read-only isReallyReadOnly = ((INHibernateProxy)proxy).HibernateLazyInitializer.ReadOnly; } } if (isReallyReadOnly) { //no need to take a snapshot - this is a //performance optimization, but not really //important, except for entities with huge //mutable property values persistenceContext.SetEntryStatus(entityEntry, Status.ReadOnly); } else { //take a snapshot TypeHelper.DeepCopy(hydratedState, persister.PropertyTypes, persister.PropertyUpdateability, hydratedState, session); persistenceContext.SetEntryStatus(entityEntry, Status.Loaded); } persister.AfterInitialize(entity, session); if (session.IsEventSource) { postLoadEvent.Entity = entity; postLoadEvent.Id = id; postLoadEvent.Persister = persister; IPostLoadEventListener[] listeners = session.Listeners.PostLoadEventListeners; for (int i = 0; i < listeners.Length; i++) { listeners[i].OnPostLoad(postLoadEvent); } } if (log.IsDebugEnabled()) { log.Debug("done materializing entity {0}", MessageHelper.InfoString(persister, id, session.Factory)); } if (stopWatch != null) { stopWatch.Stop(); factory.StatisticsImplementor.LoadEntity(persister.EntityName, stopWatch.Elapsed); } }
public static void AddUninitializedCachedEntity(EntityKey key, object obj, IEntityPersister persister, LockMode lockMode, bool lazyPropertiesAreUnfetched, object version, ISessionImplementor session) { session.PersistenceContext.AddEntity(obj, Status.Loading, null, key, version, lockMode, true, persister, false, lazyPropertiesAreUnfetched); }