/// <summary> /// Retry merging transient entities /// </summary> /// <param name="event"></param> /// <param name="transientCopyCache"></param> /// <param name="copyCache"></param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> protected async Task RetryMergeTransientEntitiesAsync(MergeEvent @event, IDictionary transientCopyCache, EventCache copyCache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // TODO: The order in which entities are saved may matter (e.g., a particular // transient entity may need to be saved before other transient entities can // be saved). // Keep retrying the batch of transient entities until either: // 1) there are no transient entities left in transientCopyCache // or 2) no transient entities were saved in the last batch. // For now, just run through the transient entities and retry the merge foreach (object entity in transientCopyCache.Keys) { object copy = transientCopyCache[entity]; EntityEntry copyEntry = @event.Session.PersistenceContext.GetEntry(copy); if (entity == @event.Entity) { await(MergeTransientEntityAsync(entity, copyEntry.EntityName, @event.RequestedId, @event.Session, copyCache, cancellationToken)).ConfigureAwait(false); } else { await(MergeTransientEntityAsync(entity, copyEntry.EntityName, copyEntry.Id, @event.Session, copyCache, cancellationToken)).ConfigureAwait(false); } } }
/// <summary> /// Retry merging transient entities /// </summary> /// <param name="event"></param> /// <param name="transientCopyCache"></param> /// <param name="copyCache"></param> protected void RetryMergeTransientEntities(MergeEvent @event, IDictionary transientCopyCache, EventCache copyCache) { // TODO: The order in which entities are saved may matter (e.g., a particular // transient entity may need to be saved before other transient entities can // be saved). // Keep retrying the batch of transient entities until either: // 1) there are no transient entities left in transientCopyCache // or 2) no transient entities were saved in the last batch. // For now, just run through the transient entities and retry the merge foreach (object entity in transientCopyCache.Keys) { object copy = transientCopyCache[entity]; EntityEntry copyEntry = @event.Session.PersistenceContext.GetEntry(copy); if (entity == @event.Entity) { MergeTransientEntity(entity, copyEntry.EntityName, @event.RequestedId, @event.Session, copyCache); } else { MergeTransientEntity(entity, copyEntry.EntityName, copyEntry.Id, @event.Session, copyCache); } } }
/// <summary> /// 触发合并单元格事件 /// </summary> /// <param name="arg0"></param> /// <param name="arg1"></param> private void Value_MergeDataEvent(CellData arg0, Vector2 arg1) { if (MergeEvent != null) { MergeEvent.Invoke(arg0, arg1); } }
/// <summary> /// Determine which merged entities in the copyCache are transient. /// </summary> /// <param name="event"></param> /// <param name="copyCache"></param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> /// <returns></returns> /// <remarks>Should this method be on the EventCache class?</remarks> protected async Task <EventCache> GetTransientCopyCacheAsync(MergeEvent @event, EventCache copyCache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); EventCache transientCopyCache = new EventCache(); foreach (object entity in copyCache.Keys) { object entityCopy = copyCache[entity]; if (entityCopy.IsProxy()) { entityCopy = await(((INHibernateProxy)entityCopy).HibernateLazyInitializer.GetImplementationAsync(cancellationToken)).ConfigureAwait(false); } // NH-specific: Disregard entities that implement ILifecycle and manage their own state - they // don't have an EntityEntry, and we can't determine if they are transient or not if (entityCopy is ILifecycle) { continue; } EntityEntry copyEntry = @event.Session.PersistenceContext.GetEntry(entityCopy); if (copyEntry == null) { // entity name will not be available for non-POJO entities // TODO: cache the entity name somewhere so that it is available to this exception log.Info( "transient instance could not be processed by merge: {0} [{1}]", @event.Session.GuessEntityName(entityCopy), entity); // merge did not cascade to this entity; it's in copyCache because a // different entity has a non-nullable reference to it; // this entity should not be put in transientCopyCache, because it was // not included in the merge; throw new TransientObjectException( "object is an unsaved transient instance - save the transient instance before merging: " + @event.Session.GuessEntityName(entityCopy)); } else if (copyEntry.Status == Status.Saving) { transientCopyCache.Add(entity, entityCopy, copyCache.IsOperatedOn(entity)); } else if (copyEntry.Status != Status.Loaded && copyEntry.Status != Status.ReadOnly) { throw new AssertionFailure( String.Format( "Merged entity does not have status set to MANAGED or READ_ONLY; {0} status = {1}", entityCopy, copyEntry.Status)); } } return(transientCopyCache); }
/// <summary> /// Handle the given merge event. /// </summary> /// <param name="event">The merge event to be handled. </param><param name="copiedAlready"/> public void OnMerge(MergeEvent @event, IDictionary copiedAlready) { try { _defaultMergeEventListener.OnMerge(@event, copiedAlready); } catch (Exception ex) { throw new InvalidOperationException("Error trying to merge: {0}".InvariantFormat(GetUsefulEntityName(@event.Entity, @event.EntityName, null)), ex); } }
public virtual async Task OnMergeAsync(MergeEvent @event, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); EventCache copyCache = new EventCache(); await(OnMergeAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false); // transientCopyCache may contain parent and child entities in random order. // Child entities occurring ahead of their respective transient parents may fail // to get merged in one iteration. // Retries are necessary as more and more children may be able to merge on subsequent iterations. // Iteratively get transient entities and retry merge until one of the following conditions is true: // 1) transientCopyCache.size() == 0 // 2) transientCopyCache.size() is not decreasing // TODO: find out if retrying can add entities to copyCache (don't think it can...) // For now, just retry once; throw TransientObjectException if there are still any transient entities IDictionary transientCopyCache = await(this.GetTransientCopyCacheAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false); while (transientCopyCache.Count > 0) { var initialTransientCount = transientCopyCache.Count; await(RetryMergeTransientEntitiesAsync(@event, transientCopyCache, copyCache, cancellationToken)).ConfigureAwait(false); // find any entities that are still transient after retry transientCopyCache = await(this.GetTransientCopyCacheAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false); // if a retry did nothing, the remaining transient entities // cannot be merged due to references to other transient entities // that are not part of the merge if (transientCopyCache.Count == initialTransientCount) { ISet <string> transientEntityNames = new HashSet <string>(); foreach (object transientEntity in transientCopyCache.Keys) { string transientEntityName = @event.Session.GuessEntityName(transientEntity); transientEntityNames.Add(transientEntityName); log.Info( "transient instance could not be processed by merge: {0} [{1}]", transientEntityName, transientEntity.ToString()); } throw new TransientObjectException("one or more objects is an unsaved transient instance - save transient instance(s) before merging: " + String.Join(",", transientEntityNames.ToArray())); } } copyCache.Clear(); }
protected virtual void EntityIsTransient(MergeEvent @event, IDictionary copyCache) { log.Info("merging transient instance"); object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity); string entityName = persister.EntityName; @event.Result = this.MergeTransientEntity(entity, entityName, @event.RequestedId, source, copyCache); }
public virtual void OnMerge(MergeEvent @event) { EventCache copyCache = new EventCache(); OnMerge(@event, copyCache); // transientCopyCache may contain parent and child entities in random order. // Child entities occurring ahead of their respective transient parents may fail // to get merged in one iteration. // Retries are necessary as more and more children may be able to merge on subsequent iterations. // Iteratively get transient entities and retry merge until one of the following conditions is true: // 1) transientCopyCache.size() == 0 // 2) transientCopyCache.size() is not decreasing // TODO: find out if retrying can add entities to copyCache (don't think it can...) // For now, just retry once; throw TransientObjectException if there are still any transient entities IDictionary transientCopyCache = this.GetTransientCopyCache(@event, copyCache); while (transientCopyCache.Count > 0) { var initialTransientCount = transientCopyCache.Count; RetryMergeTransientEntities(@event, transientCopyCache, copyCache); // find any entities that are still transient after retry transientCopyCache = this.GetTransientCopyCache(@event, copyCache); // if a retry did nothing, the remaining transient entities // cannot be merged due to references to other transient entities // that are not part of the merge if (transientCopyCache.Count == initialTransientCount) { ISet<string> transientEntityNames = new HashSet<string>(); foreach (object transientEntity in transientCopyCache.Keys) { string transientEntityName = @event.Session.GuessEntityName(transientEntity); transientEntityNames.Add(transientEntityName); log.InfoFormat( "transient instance could not be processed by merge: {0} [{1}]", transientEntityName, transientEntity.ToString()); } throw new TransientObjectException("one or more objects is an unsaved transient instance - save transient instance(s) before merging: " + String.Join(",", transientEntityNames.ToArray())); } } copyCache.Clear(); }
protected virtual async Task EntityIsTransientAsync(MergeEvent @event, IDictionary copyCache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); log.Info("merging transient instance"); object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity); string entityName = persister.EntityName; @event.Result = await(this.MergeTransientEntityAsync(entity, entityName, @event.RequestedId, source, copyCache, cancellationToken)).ConfigureAwait(false); }
public void OnMerge(MergeEvent @event, IDictionary copiedAlready) { if (@event.Entity == null) { return; } EventDispatcher.RaiseEvent(@event.Entity, typeof(UpdateEvent)); //Validate event is raised here instead of on PreInsert/PreUpdate events to make our validation before the //NHibernate DefaultSaveOrUpdateEventListener is handled since it throws own exceptions if entity isn't valid //according to its Map. EventDispatcher.RaiseEvent(@event.Entity, typeof(ValidateEvent)); }
protected virtual void EntityIsPersistent(MergeEvent @event, IDictionary copyCache) { log.Debug("ignoring persistent instance"); //TODO: check that entry.getIdentifier().equals(requestedId) object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity); copyCache[entity] = entity; //before cascade! CascadeOnMerge(source, persister, entity, copyCache); CopyValues(persister, entity, entity, source, copyCache); @event.Result = entity; }
public virtual void OnMerge(MergeEvent @event) { EventCache copyCache = new EventCache(); OnMerge(@event, copyCache); // TODO: iteratively get transient entities and retry merge until one of the following conditions: // 1) transientCopyCache.size() == 0 // 2) transientCopyCache.size() is not decreasing and copyCache.size() is not increasing // TODO: find out if retrying can add entities to copyCache (don't think it can...) // For now, just retry once; throw TransientObjectException if there are still any transient entities IDictionary transientCopyCache = this.GetTransientCopyCache(@event, copyCache); if (transientCopyCache.Count > 0) { RetryMergeTransientEntities(@event, transientCopyCache, copyCache); // find any entities that are still transient after retry transientCopyCache = this.GetTransientCopyCache(@event, copyCache); if (transientCopyCache.Count > 0) { ISet <string> transientEntityNames = new HashedSet <string>(); foreach (object transientEntity in transientCopyCache.Keys) { string transientEntityName = @event.Session.GuessEntityName(transientEntity); transientEntityNames.Add(transientEntityName); log.InfoFormat( "transient instance could not be processed by merge: {0} [{1}]", transientEntityName, transientEntity.ToString()); } throw new TransientObjectException("one or more objects is an unsaved transient instance - save transient instance(s) before merging: " + transientEntityNames); } } copyCache.Clear(); copyCache = null; }
public virtual void OnMerge(MergeEvent @event) { EventCache copyCache = new EventCache(); OnMerge(@event, copyCache); // TODO: iteratively get transient entities and retry merge until one of the following conditions: // 1) transientCopyCache.size() == 0 // 2) transientCopyCache.size() is not decreasing and copyCache.size() is not increasing // TODO: find out if retrying can add entities to copyCache (don't think it can...) // For now, just retry once; throw TransientObjectException if there are still any transient entities IDictionary transientCopyCache = this.GetTransientCopyCache(@event, copyCache); if (transientCopyCache.Count > 0) { RetryMergeTransientEntities(@event, transientCopyCache, copyCache); // find any entities that are still transient after retry transientCopyCache = this.GetTransientCopyCache(@event, copyCache); if (transientCopyCache.Count > 0) { ISet<string> transientEntityNames = new HashedSet<string>(); foreach (object transientEntity in transientCopyCache.Keys) { string transientEntityName = @event.Session.GuessEntityName(transientEntity); transientEntityNames.Add(transientEntityName); log.InfoFormat( "transient instance could not be processed by merge: {0} [{1}]", transientEntityName, transientEntity.ToString()); } throw new TransientObjectException("one or more objects is an unsaved transient instance - save transient instance(s) before merging: " + transientEntityNames); } } copyCache.Clear(); copyCache = null; }
protected virtual async Task EntityIsPersistentAsync(MergeEvent @event, IDictionary copyCache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); log.Debug("ignoring persistent instance"); //TODO: check that entry.getIdentifier().equals(requestedId) object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity); ((EventCache)copyCache).Add(entity, entity, true); //before cascade! await(CascadeOnMergeAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false); await(CopyValuesAsync(persister, entity, entity, source, copyCache, cancellationToken)).ConfigureAwait(false); @event.Result = entity; }
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; }
private void DoMerge(MergeEvent @event) { var entity = ValidateOblect(@event.Original); if (entity != null) { var entityEntry = @event.Session.PersistenceContext.GetEntry(entity); if (entityEntry == null) { return; } object[] currentState; var modified = IsEntityModified(entityEntry, entity, @event.Session, out currentState); if (modified) { PackageAuditLogItem(EventType.Modified, entityEntry.Persister, entity as IRootEntity <idT>, currentState, entityEntry.LoadedState); } } }
private void Update() { if (MergeEvents.Count > 0 && Cando) { //Cando=false; MergeEvent _MergeEvent = MergeEvents.Dequeue(); if (_MergeEvent.SphereA != null && _MergeEvent.SphereB != null) { _MergeEvent.SphereA.RefreshSphere(_MergeEvent.SphereB); } if (Config.Instance.mList.Contains(_MergeEvent.SphereA.id + "_" + _MergeEvent.SphereB.id)) { Config.Instance.mList.Remove(_MergeEvent.SphereA.id + "_" + _MergeEvent.SphereB.id); } if (Config.Instance.mList.Contains(_MergeEvent.SphereB.id + "_" + _MergeEvent.SphereA.id)) { Config.Instance.mList.Remove(_MergeEvent.SphereB.id + "_" + _MergeEvent.SphereA.id); } } }
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 void OnMerge(MergeEvent @event, System.Collections.IDictionary copiedAlready) { }
public void OnMerge(MergeEvent @event) { }
public Task OnMergeAsync(MergeEvent @event, IDictionary copiedAlready, CancellationToken cancellationToken) { EnsureTransaction(@event); return(Task.FromResult(true)); }
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)); } } } }
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(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; }
public void OnMerge(MergeEvent @event, IDictionary copiedAlready) { ResetReadOnlyEntity(@event.Session, @event.Original); }
public override async Task OnMergeAsync(MergeEvent evt, CancellationToken cancellationToken) { eventListenerHelper.OnModify(evt.Original); await base.OnMergeAsync(evt, cancellationToken); }
/// <summary> /// Retry merging transient entities /// </summary> /// <param name="event"></param> /// <param name="transientCopyCache"></param> /// <param name="copyCache"></param> protected void RetryMergeTransientEntities(MergeEvent @event, IDictionary transientCopyCache, EventCache copyCache) { // TODO: The order in which entities are saved may matter (e.g., a particular // transient entity may need to be saved before other transient entities can // be saved). // Keep retrying the batch of transient entities until either: // 1) there are no transient entities left in transientCopyCache // or 2) no transient entities were saved in the last batch. // For now, just run through the transient entities and retry the merge foreach(object entity in transientCopyCache.Keys) { object copy = transientCopyCache[entity]; EntityEntry copyEntry = @event.Session.PersistenceContext.GetEntry(copy); if (entity == @event.Entity) MergeTransientEntity(entity, copyEntry.EntityName, @event.RequestedId, @event.Session, copyCache); else MergeTransientEntity(entity, copyEntry.EntityName, copyEntry.Id, @event.Session, copyCache); } }
public void OnMerge(MergeEvent @event) { OnMerge(@event, null); }
public virtual void OnMerge(MergeEvent @event) { OnMerge(@event, IdentityMap.Instantiate(10)); }
public virtual void OnMerge(MergeEvent @event) { OnMerge(@event, IdentityMap.Instantiate(10)); }
protected virtual void EntityIsTransient(MergeEvent @event, IDictionary copyCache) { log.Info("merging transient instance"); object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity); string entityName = persister.EntityName; @event.Result = this.MergeTransientEntity(entity, entityName, @event.RequestedId, source, copyCache); }
/// <summary> /// 返回新的规则集 /// </summary> /// <param name="thresholdToRemove">如果为<see cref="int.MaxValue"/>则只去除重复,不进行合并。</param> /// <returns></returns> public List <UMatrixRule> Clean(int thresholdToRemove) { HashSet <UMatrixRule> processedRules = new HashSet <UMatrixRule>(); savedSearch = 0; List <UMatrixRule> newRules = new List <UMatrixRule>(); for (int i = 0; i < rules.Count; i++) { var currentRule = rules[i]; var g = currentRule.Selector; bool isGeneralized = false; while (g != null) { var generalizedRule = new UMatrixRule(g.Source, g.Destination, g.Type, currentRule.IsAllow); if (processedRules.Contains(generalizedRule)) { savedSearch++; break; } var subRules = (from r in rules where g.IsProperSuperOf(r.Selector) && r.IsAllow == currentRule.IsAllow select r).ToArray(); if (subRules.Length >= (isGeneralized ? thresholdToRemove : 1)) { var toRemove = new List <UMatrixRule>(); foreach (var subRule in subRules) { var superOrJointRules = this.GetSuperOrJointRules(subRule).Union(newRules.Where(nr => nr.Selector.IsSuperOrHasJoint(subRule.Selector))).Where(r => r.IsAllow != subRule.IsAllow); if (superOrJointRules.Any(s => s.Priority > generalizedRule.Priority) || generalizedRule.IsAllow && generalizedRule.Selector.Type == TypePredicate.All && subRule.Selector.Type != TypePredicate.All) { //不能删除 } else { toRemove.Add(subRule); } } Debug.Assert(toRemove.Contains(currentRule) || toRemove.Contains(currentRule) == false, "当前规则可能被更高优先级规则锁定,但当前规则的推广规则可能可用于合并其他规则。"); var groupings = toRemove.GroupBy(r => r.Selector.GetDistanceTo(generalizedRule.Selector)).ToArray(); MergeEventArgs me = null; DedupRuleEventArgs de = null; foreach (var grouping in groupings) { if (grouping.Count() >= (isGeneralized ? GetDistance(grouping.Key) * thresholdToRemove : 1)) { newRules.Add(generalizedRule); if (isGeneralized) { if (me == null) { me = new MergeEventArgs(); } me.MasterRule = generalizedRule; me.RulesToDelete.AddRange(grouping); } else { if (de == null) { de = new DedupRuleEventArgs(); } de.MasterRule = generalizedRule; de.DuplicateRules.AddRange(grouping); } for (int j = rules.Count - 1; j >= i; j--) { if (grouping.Contains(rules[j])) { RemoveFromRelationshipTable(rules[j]); rules[j] = rules[rules.Count - 1]; rules.RemoveAt(rules.Count - 1); } } } } if (me != null) { MergeEvent?.Invoke(this, me); } if (de != null) { DedupEvent?.Invoke(this, de); } processedRules.Add(generalizedRule); break; } g = g.Generalize(); isGeneralized = true; if (thresholdToRemove == Int32.MaxValue) { break; } } } logger.LogDebug("变量{0}节省了{1}次查询。", nameof(processedRules), savedSearch); foreach (var newRule in newRules) { if (rules.Contains(newRule) == false) { rules.Add(newRule); } } return(rules.ToList()); }
/// <summary> /// Perfome merge /// </summary> /// <param name="evt">The save or update event.</param> /// <returns> /// The id used to save the entity; may be null depending on the /// type of id generator used and the requiresImmediateIdAccess value /// </returns> public override void OnMerge(MergeEvent evt) { eventListenerHelper.OnModify(evt.Entity); base.OnMerge(evt); }
public void OnMerge(MergeEvent @event) { @event.EntityName = GetEntityName(@event.Original, @event.EntityName); }
public void OnMerge(MergeEvent @event, IDictionary copiedAlready) { ExplicitUpdateCall(@event.Entity as ITrackModificationDate); }
protected virtual void EntityIsPersistent(MergeEvent @event, IDictionary copyCache) { log.Debug("ignoring persistent instance"); //TODO: check that entry.getIdentifier().equals(requestedId) object entity = @event.Entity; IEventSource source = @event.Session; IEntityPersister persister = source.GetEntityPersister(entity); copyCache[entity] = entity; //before cascade! CascadeOnMerge(source, persister, entity, copyCache); CopyValues(persister, entity, entity, source, copyCache); @event.Result = entity; }
public void OnMerge(MergeEvent @event) { ExplicitUpdateCall(@event.Entity as ITrackModificationDate); }
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 { 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; } }
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)); } } } }
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)); } } } }
/// <summary> /// Determine which merged entities in the copyCache are transient. /// </summary> /// <param name="event"></param> /// <param name="copyCache"></param> /// <returns></returns> /// <remarks>Should this method be on the EventCache class?</remarks> protected EventCache GetTransientCopyCache(MergeEvent @event, EventCache copyCache) { EventCache transientCopyCache = new EventCache(); foreach(object entity in copyCache.Keys) { object entityCopy = copyCache[entity]; if (entityCopy.IsProxy()) entityCopy = ((INHibernateProxy)entityCopy).HibernateLazyInitializer.GetImplementation(); // NH-specific: Disregard entities that implement ILifecycle and manage their own state - they // don't have an EntityEntry, and we can't determine if they are transient or not if (entityCopy is ILifecycle) continue; EntityEntry copyEntry = @event.Session.PersistenceContext.GetEntry(entityCopy); if (copyEntry == null) { // entity name will not be available for non-POJO entities // TODO: cache the entity name somewhere so that it is available to this exception log.InfoFormat( "transient instance could not be processed by merge: {0} [{1}]", @event.Session.GuessEntityName(entityCopy), entity); // merge did not cascade to this entity; it's in copyCache because a // different entity has a non-nullable reference to it; // this entity should not be put in transientCopyCache, because it was // not included in the merge; throw new TransientObjectException( "object is an unsaved transient instance - save the transient instance before merging: " + @event.Session.GuessEntityName(entityCopy)); } else if (copyEntry.Status == Status.Saving) { transientCopyCache.Add(entity, entityCopy, copyCache.IsOperatedOn(entity)); } else if (copyEntry.Status != Status.Loaded && copyEntry.Status != Status.ReadOnly) { throw new AssertionFailure( String.Format( "Merged entity does not have status set to MANAGED or READ_ONLY; {0} status = {1}", entityCopy, copyEntry.Status)); } } return transientCopyCache; }