public AuditProcess Get(IEventSource session)
        {
            var transaction = session.Transaction;

            AuditProcess auditProcess;

            if (!_auditProcesses.TryGetValue(transaction, out auditProcess))
            {
                // No worries about registering a transaction twice - a transaction is single thread
                auditProcess = new AuditProcess(_revisionInfoGenerator, session);
                _auditProcesses[transaction] = auditProcess;

                session.ActionQueue.RegisterProcess(() =>
                {
                    AuditProcess currentProcess;
                    if (_auditProcesses.TryGetValue(transaction, out currentProcess))
                    {
                        currentProcess.DoBeforeTransactionCompletion();
                    }
                });
                session.ActionQueue.RegisterProcess(success => _auditProcesses.Remove(transaction));
            }

            return(auditProcess);
        }
예제 #2
0
        public AuditProcess Get(IEventSource session)
        {
            var transaction = session.Transaction;

            if (!_auditProcesses.TryGetValue(transaction, out var auditProcess))
            {
                // No worries about registering a transaction twice - a transaction is single thread
                auditProcess = new AuditProcess(_revisionInfoGenerator, session);
                _auditProcesses[transaction] = auditProcess;
                var tranProcess = new transactionCompletionProcess(_auditProcesses, transaction);
                session.ActionQueue.RegisterProcess((IBeforeTransactionCompletionProcess)tranProcess);
                session.ActionQueue.RegisterProcess((IAfterTransactionCompletionProcess)tranProcess);
            }

            return(auditProcess);
        }
예제 #3
0
        public AuditProcess Get(IEventSource session)
        {
            var transaction = session.Transaction;

            AuditProcess auditProcess;
            if (!auditProcesses.TryGetValue(transaction, out auditProcess))
            {
                // No worries about registering a transaction twice - a transaction is single thread
                auditProcess = new AuditProcess(revisionInfoGenerator, session);
                auditProcesses[transaction] = auditProcess;

                session.ActionQueue.RegisterProcess(auditProcess.DoBeforeTransactionCompletion);
                session.ActionQueue.RegisterProcess(success => auditProcesses.Remove(transaction));
            }

            return auditProcess;
        }
예제 #4
0
        private void GenerateFakeBidirecationalRelationWorkUnits(AuditProcess auditProcess,
																IPersistentCollection newColl,
																object oldColl,
																string collectionEntityName,
																string referencingPropertyName,
																AbstractCollectionEvent evt,
																RelationDescription rd)
        {
            // First computing the relation changes
            var collectionChanges = VerCfg.EntCfg[collectionEntityName].PropertyMapper
                    .MapCollectionChanges(referencingPropertyName, newColl, oldColl, evt.AffectedOwnerIdOrNull);

            // Getting the id mapper for the related entity, as the work units generated will corrspond to the related
            // entities.
            var relatedEntityName = rd.ToEntityName;
            var relatedIdMapper = VerCfg.EntCfg[relatedEntityName].IdMapper;

            // For each collection change, generating the bidirectional work unit.
            foreach (var changeData in collectionChanges)
            {
                var relatedObj = changeData.GetChangedElement();
                var relatedId = relatedIdMapper.MapToIdFromEntity(relatedObj);
                var revType = (RevisionType)changeData.Data[VerCfg.AuditEntCfg.RevisionTypePropName];

                // This can be different from relatedEntityName, in case of inheritance (the real entity may be a subclass
                // of relatedEntityName).
                var realRelatedEntityName = evt.Session.BestGuessEntityName(relatedObj);

                // By default, the nested work unit is a collection change work unit.
                var nestedWorkUnit = new CollectionChangeWorkUnit(evt.Session, realRelatedEntityName, VerCfg,
                        relatedId, relatedObj);

                auditProcess.AddWorkUnit(new FakeBidirectionalRelationWorkUnit(evt.Session, realRelatedEntityName, VerCfg,
                        relatedId, referencingPropertyName, evt.AffectedOwnerOrNull, rd, revType,
                        changeData.GetChangedElementIndex(), nestedWorkUnit));
            }

            // We also have to generate a collection change work unit for the owning entity.
            auditProcess.AddWorkUnit(new CollectionChangeWorkUnit(evt.Session, collectionEntityName, VerCfg,
                    evt.AffectedOwnerIdOrNull, evt.AffectedOwnerOrNull));
        }
예제 #5
0
        private void GenerateBidirectionalCollectionChangeWorkUnits(AuditProcess auditProcess,
																	IDatabaseEventArgs evt,
																	PersistentCollectionChangeWorkUnit workUnit,
																	RelationDescription rd)
        {
            // Checking if this is enabled in configuration ...
            if (!VerCfg.GlobalCfg.GenerateRevisionsForCollections)
                return;

            // Checking if this is not a bidirectional relation - then, a revision needs also be generated for
            // the other side of the relation.
            // relDesc can be null if this is a collection of simple values (not a relation).
            if (rd != null && rd.Bidirectional)
            {
                var relatedEntityName = rd.ToEntityName;
                var relatedIdMapper = VerCfg.EntCfg[relatedEntityName].IdMapper;

                foreach (var changeData in workUnit.CollectionChanges)
                {
                    var relatedObj = changeData.GetChangedElement();
                    var relatedId = relatedIdMapper.MapToIdFromEntity(relatedObj);

                    auditProcess.AddWorkUnit(new CollectionChangeWorkUnit(evt.Session,
                                                                                            evt.Session.BestGuessEntityName(relatedObj),
                                                                                            VerCfg,
                                                                                            relatedId,
                                                                                            relatedObj));
                }
            }
        }
예제 #6
0
        private void GenerateBidirectionalCollectionChangeWorkUnits(AuditProcess auditProcess,
																	IEntityPersister entityPersister,
																	string entityName,
																	IList<object> newState,
																	IList<object> oldState,
																	ISessionImplementor session)
        {
            // Checking if this is enabled in configuration ...
            if (!VerCfg.GlobalCfg.GenerateRevisionsForCollections)
                return;

            // Checks every property of the entity, if it is an "owned" to-one relation to another entity.
            // If the value of that property changed, and the relation is bi-directional, a new revision
            // for the related entity is generated.
            var propertyNames = entityPersister.PropertyNames;

            for (var i = 0; i < propertyNames.GetLength(0); i++)
            {
                var propertyName = propertyNames[i];
                var relDesc = VerCfg.EntCfg.GetRelationDescription(entityName, propertyName);
                if (relDesc != null &&
                    relDesc.Bidirectional &&
                    relDesc.RelationType == RelationType.ToOne &&
                    relDesc.Insertable)
                {
                    // Checking for changes
                    var oldValue = oldState == null ? null : oldState[i];
                    var newValue = newState == null ? null : newState[i];

                    if (!Toolz.EntitiesEqual(session, oldValue, newValue))
                    {
                        // We have to generate changes both in the old collection (size decreses) and new collection
                        // (size increases).
                        if (newValue != null)
                        {
                            addCollectionChangeWorkUnitToAuditProcess(session, auditProcess, newValue);
                        }
                        if (oldValue != null)
                        {
                            addCollectionChangeWorkUnitToAuditProcess(session, auditProcess, oldValue);
                        }
                    }
                }
            }
        }
예제 #7
0
        private void addCollectionChangeWorkUnitToAuditProcess(ISessionImplementor session, AuditProcess auditProcess, object value)
        {
            // relDesc.getToEntityName() doesn't always return the entity name of the value - in case
            // of subclasses, this will be root class, no the actual class. So it can't be used here.
            string toEntityName;
            object id;

            var newValueAsProxy = value as INHibernateProxy;
            if (newValueAsProxy != null)
            {
                toEntityName = session.BestGuessEntityName(value);
                id = newValueAsProxy.HibernateLazyInitializer.Identifier;
                // We've got to initialize the object from the proxy to later read its state.
                value = Toolz.GetTargetFromProxy((ISession) session, newValueAsProxy);
            }
            else
            {
                toEntityName = session.GuessEntityName(value);

                var idMapper = VerCfg.EntCfg[toEntityName].IdMapper;
                id = idMapper.MapToIdFromEntity(value);
            }

            auditProcess.AddWorkUnit(new CollectionChangeWorkUnit(session, toEntityName, VerCfg, id, value));
        }