Exemple #1
0
        /// <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);
                }
            }
        }
Exemple #3
0
 /// <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);
     }
 }
Exemple #4
0
        /// <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);
        }
Exemple #5
0
 /// <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);
     }
 }
Exemple #6
0
        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();
		}
Exemple #9
0
        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);
        }
Exemple #10
0
        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;
        }
Exemple #12
0
        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;
		}
Exemple #14
0
        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;
        }
Exemple #16
0
        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);
                }
            }
        }
Exemple #17
0
    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);
            }
        }
    }
Exemple #18
0
        protected virtual async Task EntityIsDetachedAsync(MergeEvent @event, IDictionary copyCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("merging detached instance");

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

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

            object id = @event.RequestedId;

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

            string previousFetchProfile = source.FetchProfile;

            source.FetchProfile = "merge";

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

            source.FetchProfile = previousFetchProfile;

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

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

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

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

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

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

                @event.Result = result;
            }
        }
 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));
 }
Exemple #22
0
        public virtual async Task OnMergeAsync(MergeEvent @event, IDictionary copiedAlready, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            EventCache   copyCache = (EventCache)copiedAlready;
            IEventSource source    = @event.Session;
            object       original  = @event.Original;

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

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

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

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

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

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

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

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

                    default:
                        throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
                    }
                }
            }
        }
		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);
 }
Exemple #25
0
 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);
		}
Exemple #31
0
        /// <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());
        }
Exemple #32
0
 /// <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);
 }
Exemple #33
0
 public void OnMerge(MergeEvent @event)
 {
     @event.EntityName = GetEntityName(@event.Original, @event.EntityName);
 }
Exemple #34
0
 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;
		}
Exemple #36
0
 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;
		}