Esempio n. 1
0
        private XElement createMiddleEntityXml(string auditMiddleTableName, string auditMiddleEntityName, string where)
        {
            var schema  = _mainGenerator.GetSchema(_propertyAuditingData.JoinTable.Schema, _propertyValue.CollectionTable);
            var catalog = _mainGenerator.GetCatalog(_propertyAuditingData.JoinTable.Catalog, _propertyValue.CollectionTable);

            var middleEntityXml = MetadataTools.CreateEntity(_xmlMappingData.NewAdditionalMapping(),
                                                             new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null, false);
            var middleEntityXmlId = new XElement(MetadataTools.CreateElementName("composite-id"),
                                                 new XAttribute("name", _mainGenerator.VerEntCfg.OriginalIdPropName));

            middleEntityXml.Add(middleEntityXmlId);

            // If there is a where clause on the relation, adding it to the middle entity.
            if (where != null)
            {
                middleEntityXml.Add(new XAttribute("where", where));
            }

            // Adding the revision number as a foreign key to the revision info entity to the composite id of the
            // middle table.
            _mainGenerator.AddRevisionInfoRelation(middleEntityXmlId);

            // Adding the revision type property to the entity xml.
            _mainGenerator.AddRevisionType(isEmbeddableElementType() ? middleEntityXmlId : middleEntityXml, middleEntityXml);

            // All other properties should also be part of the primary key of the middle entity.
            return(middleEntityXmlId);
        }
        private Triple<XmlElement, IExtendedPropertyMapper, String> GenerateInheritanceMappingData(
                PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
                String inheritanceMappingType)
        {
            String extendsEntityName = VerEntCfg.GetAuditEntityName(pc.Superclass.EntityName);
            XmlElement class_mapping = MetadataTools.CreateSubclassEntity(xmlMappingData.MainXmlMapping,
                    inheritanceMappingType, auditTableData, extendsEntityName, pc.DiscriminatorValue);

            // The id and revision type is already mapped in the parent

            // Getting the property mapper of the parent - when mapping properties, they need to be included
            String parentEntityName = pc.Superclass.EntityName;

            EntityConfiguration parentConfiguration = EntitiesConfigurations[parentEntityName];
            if (parentConfiguration == null)
            {
                throw new MappingException("Entity '" + pc.EntityName + "' is audited, but its superclass: '" +
                        parentEntityName + "' is not.");
            }

            IExtendedPropertyMapper parentPropertyMapper = parentConfiguration.PropertyMapper;
            IExtendedPropertyMapper propertyMapper = new SubclassPropertyMapper(new MultiPropertyMapper(), parentPropertyMapper);

            return Triple<XmlElement, IExtendedPropertyMapper, String>.Make<XmlElement, IExtendedPropertyMapper, String>(class_mapping, propertyMapper, parentEntityName);
        }
Esempio n. 3
0
 private void addModifiedFlagIfNeeded(XElement parent, PropertyAuditingData propertyAuditingData, bool processModifiedFlag)
 {
     if (processModifiedFlag && propertyAuditingData.UsingModifiedFlag)
     {
         MetadataTools.AddModifiedFlagProperty(parent, propertyAuditingData.Name, GlobalCfg.ModifiedFlagSuffix);
     }
 }
 public void AddRevisionType(XmlElement any_mapping)
 {
     XmlElement revTypeProperty = MetadataTools.AddProperty(any_mapping, VerEntCfg.RevisionTypePropName,
             VerEntCfg.RevisionTypePropType, true, false);
     //TODO Simon Replace with typeof(NHibernate.Envers.Entities.RevisionTypeType).FullName
     revTypeProperty.SetAttribute("type", "NHibernate.Envers.Entities.RevisionTypeType, Envers.NET");
 }
Esempio n. 5
0
        private void createJoins(PersistentClass pc, XElement parent, ClassAuditingData auditingData)
        {
            var joinElements = new Dictionary <Join, XElement>();

            entitiesJoins.Add(pc.EntityName, joinElements);

            foreach (var join in pc.JoinIterator)
            {
                // Checking if any of the join properties are audited
                if (!checkAnyPropertyAudited(join.PropertyIterator, auditingData))
                {
                    continue;
                }

                // Determining the table name. If there is no entry in the dictionary, just constructing the table name
                // as if it was an entity (by appending/prepending configured strings).
                string auditTableName;
                if (!auditingData.JoinTableDictionary.TryGetValue(join.Table.Name, out auditTableName))
                {
                    auditTableName = VerEntCfg.JoinTableName(join);
                }

                var schema  = GetSchema(auditingData.AuditTable.Schema, join.Table);
                var catalog = GetCatalog(auditingData.AuditTable.Catalog, join.Table);

                var joinElement = MetadataTools.CreateJoin(parent, auditTableName, schema, catalog);
                joinElements.Add(join, joinElement);

                var joinKey = new XElement(MetadataTools.CreateElementName("key"));
                joinElement.Add(joinKey);
                MetadataTools.AddColumns(joinKey, join.Key.ColumnIterator.OfType <Column>());
                MetadataTools.AddColumn(joinKey, VerEntCfg.RevisionFieldName, -1, -1, -1, null, false);
            }
        }
Esempio n. 6
0
        private Tuple <XElement, IExtendedPropertyMapper, string> generateInheritanceMappingData(
            PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
            string inheritanceMappingType)
        {
            var extendsEntityName = VerEntCfg.GetAuditEntityName(pc.Superclass.EntityName);
            var hasDiscriminator  = pc.Discriminator != null;
            var classMapping      = MetadataTools.CreateSubclassEntity(xmlMappingData.MainXmlMapping,
                                                                       inheritanceMappingType, auditTableData, extendsEntityName, hasDiscriminator ? pc.DiscriminatorValue : null,
                                                                       pc.IsAbstract.HasValue && pc.IsAbstract.Value);

            // The id and revision type is already mapped in the parent

            // Getting the property mapper of the parent - when mapping properties, they need to be included
            var parentEntityName = pc.Superclass.EntityName;

            EntityConfiguration parentConfiguration;

            if (!EntitiesConfigurations.TryGetValue(parentEntityName, out parentConfiguration))
            {
                throw new MappingException("Entity '" + pc.EntityName + "' is audited, but its superclass: '" + parentEntityName + "' is not.");
            }

            var parentPropertyMapper = parentConfiguration.PropertyMapper;
            var propertyMapper       = new SubclassPropertyMapper(new MultiPropertyMapper(), parentPropertyMapper);

            return(new Tuple <XElement, IExtendedPropertyMapper, string>(classMapping, propertyMapper, parentEntityName));
        }
Esempio n. 7
0
        private Tuple <XElement, IExtendedPropertyMapper, string> generateMappingData(
            PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
            IdMappingData idMapper)
        {
            var hasDiscriminator = pc.Discriminator != null;

            var classMapping = MetadataTools.CreateEntity(xmlMappingData.MainXmlMapping, auditTableData,
                                                          hasDiscriminator ? pc.DiscriminatorValue : null, pc.IsAbstract.HasValue && pc.IsAbstract.Value);
            var propertyMapper = new MultiPropertyMapper();

            // Adding the id mapping
            classMapping.Add(idMapper.XmlMapping);

            // Checking if there is a discriminator column
            if (hasDiscriminator)
            {
                var discriminatorElement = new XElement(MetadataTools.CreateElementName("discriminator"));
                classMapping.Add(discriminatorElement);
                // Database column or SQL formula allowed to distinguish entity types
                MetadataTools.AddColumnsOrFormulas(discriminatorElement, pc.Discriminator.ColumnIterator);
                discriminatorElement.Add(new XAttribute("type", pc.Discriminator.Type.Name));
            }

            // Adding the "revision type" property
            AddRevisionType(classMapping, classMapping);

            return(new Tuple <XElement, IExtendedPropertyMapper, string>(classMapping, propertyMapper, null));
        }
Esempio n. 8
0
        private XmlElement CreateMiddleEntityXml(String auditMiddleTableName, String auditMiddleEntityName, String where)
        {
            String schema  = mainGenerator.GetSchema(propertyAuditingData.JoinTable.Schema, propertyValue.CollectionTable);
            String catalog = mainGenerator.GetCatalog(propertyAuditingData.JoinTable.Catalog, propertyValue.CollectionTable);

            XmlElement middleEntityXml = MetadataTools.CreateEntity(xmlMappingData.newAdditionalMapping(),
                                                                    new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog), null);
            XmlElement middleEntityXmlId = middleEntityXml.OwnerDocument.CreateElement("composite-id");

            middleEntityXml.AppendChild(middleEntityXmlId);

            // If there is a where clause on the relation, adding it to the middle entity.
            if (where != null)
            {
                middleEntityXml.SetAttribute("where", where);
            }

            middleEntityXmlId.SetAttribute("name", mainGenerator.VerEntCfg.OriginalIdPropName);

            // Adding the revision number as a foreign key to the revision info entity to the composite id of the
            // middle table.
            mainGenerator.AddRevisionInfoRelation(middleEntityXmlId);

            // Adding the revision type property to the entity xml.
            mainGenerator.AddRevisionType(middleEntityXml);

            // All other properties should also be part of the primary key of the middle entity.
            return(middleEntityXmlId);
        }
Esempio n. 9
0
        private static void addCustomValue(XElement parent, PropertyAuditingData propertyAuditingData,
                                           IValue value, ISimpleMapperBuilder mapper, bool insertable,
                                           bool key, System.Type typeOfUserImplementation)
        {
            if (parent != null)
            {
                var propMapping = MetadataTools.AddProperty(parent, propertyAuditingData.Name,
                                                            typeOfUserImplementation.AssemblyQualifiedName, insertable, key);
                MetadataTools.AddColumns(propMapping, value.ColumnIterator.OfType <Column>());
                var typeElement = new XElement(MetadataTools.CreateElementName("type"),
                                               new XAttribute("name", typeOfUserImplementation.AssemblyQualifiedName));

                var simpleValue = value as SimpleValue;
                if (simpleValue != null)
                {
                    var typeParameters = simpleValue.TypeParameters;
                    if (typeParameters != null)
                    {
                        foreach (var paramKeyValue in typeParameters)
                        {
                            var typeParam = new XElement(MetadataTools.CreateElementName("param"),
                                                         new XAttribute("name", paramKeyValue.Key), paramKeyValue.Value);
                            typeElement.Add(typeParam);
                        }
                    }
                }
                propMapping.Add(typeElement);
            }

            if (mapper != null)
            {
                mapper.Add(propertyAuditingData.GetPropertyData());
            }
        }
        /**
         * Clones the revision info relation mapping, so that it can be added to other mappings. Also, the name of
         * the property and the column are set properly.
         * @return A revision info mapping, which can be added to other mappings (has no parent).
         */
        private XmlElement CloneAndSetupRevisionInfoRelationMapping(XmlDocument doc)
        {
            XmlElement rev_mapping = (XmlElement)doc.ImportNode(revisionInfoRelationMapping, true);
            rev_mapping.SetAttribute("name", VerEntCfg.RevisionFieldName);

            MetadataTools.AddOrModifyColumn(rev_mapping, VerEntCfg.RevisionFieldName);

            return rev_mapping;
        }
        public void AddKeyManyToOne(XElement parent, PropertyAuditingData propertyAuditingData, IValue value, ISimpleMapperBuilder mapper)
        {
            var type    = value.Type;
            var element = mapper == null?
                          MetadataTools.AddKeyManyToOne(parent, propertyAuditingData.Name, type.ReturnedClass.AssemblyQualifiedName) :
                              MetadataTools.AddManyToOne(parent, propertyAuditingData.Name, type.ReturnedClass.AssemblyQualifiedName, true, false);

            MetadataTools.AddColumns(element, value.ColumnIterator.OfType <Column>());
            mapper?.Add(propertyAuditingData.GetPropertyData());
        }
Esempio n. 12
0
        /// <summary>
        ///  Clones the revision info relation mapping, so that it can be added to other mappings. Also, the name of
        ///  the property and the column are set properly.
        /// </summary>
        /// <returns>A revision info mapping, which can be added to other mappings (has no parent).</returns>
        private XElement cloneAndSetupRevisionInfoRelationMapping()
        {
            var revMapping = new XElement(revisionInfoRelationMapping);

            revMapping.Add(new XAttribute("name", VerEntCfg.RevisionFieldName));

            MetadataTools.AddOrModifyColumn(revMapping, VerEntCfg.RevisionFieldName);

            return(revMapping);
        }
Esempio n. 13
0
        /**
         *
         * @param value Value, which should be mapped to the middle-table, either as a relation to another entity,
         * or as a simple value.
         * @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this element.
         * @param queryGeneratorBuilder In case <code>value</code> is a relation to another entity, information about it
         * should be added to the given.
         * @param prefix Prefix for proeprty names of related entities identifiers.
         * @param joinColumns Names of columns to use in the xml mapping, if this array isn't null and has any elements.
         * @return Data for mapping this component.
         */
        //@SuppressWarnings({"unchecked"})
        private MiddleComponentData AddValueToMiddleTable(IValue value, XmlElement xmlMapping,
                                                          QueryGeneratorBuilder queryGeneratorBuilder,
                                                          String prefix, JoinColumnAttribute[] joinColumns)
        {
            IType type = value.Type;

            if (type is ManyToOneType)
            {
                String prefixRelated = prefix + "_";

                String referencedEntityName = MappingTools.getReferencedEntityName(value);

                IdMappingData referencedIdMapping = mainGenerator.GetReferencedIdMappingData(referencingEntityName,
                                                                                             referencedEntityName, propertyAuditingData, true);

                // Adding related-entity (in this case: the referenced entities id) id mapping to the xml only if the
                // relation isn't inverse (so when <code>xmlMapping</code> is not null).
                if (xmlMapping != null)
                {
                    AddRelatedToXmlMapping(xmlMapping, prefixRelated,
                                           joinColumns != null && joinColumns.Length > 0
                                    ? MetadataTools.GetColumnNameEnumerator(joinColumns)
                                    : MetadataTools.GetColumnNameEnumerator(value.ColumnIterator.GetEnumerator()),
                                           referencedIdMapping);
                }

                // Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
                MiddleIdData referencedIdData = CreateMiddleIdData(referencedIdMapping,
                                                                   prefixRelated, referencedEntityName);
                // And adding it to the generator builder.
                queryGeneratorBuilder.AddRelation(referencedIdData);

                return(new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
                                               queryGeneratorBuilder.CurrentIndex));
            }
            else
            {
                // Last but one parameter: collection components are always insertable
                bool mapped = mainGenerator.BasicMetadataGenerator.AddBasic(xmlMapping,
                                                                            new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false),
                                                                            value, null, true, true);

                if (mapped)
                {
                    // Simple values are always stored in the first item of the array returned by the query generator.
                    return(new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.VerEntCfg, prefix), 0));
                }
                else
                {
                    mainGenerator.ThrowUnsupportedTypeException(type, referencingEntityName, propertyName);
                    // Impossible to get here.
                    throw new AssertionFailure();
                }
            }
        }
        public IdMappingData AddId(PersistentClass pc)
        {
            var relIdMapping = new XElement(MetadataTools.CreateElementName("properties"));
            // Xml mapping which will be used for the primary key of the versions table
            var origIdMapping = new XElement(MetadataTools.CreateElementName("composite-id"),
                                             new XAttribute("name", _mainGenerator.VerEntCfg.OriginalIdPropName));

            var idProp   = pc.IdentifierProperty;
            var idMapper = pc.IdentifierMapper;

            // Checking if the id mapping is supported
            if (idMapper == null && idProp == null)
            {
                return(null);
            }

            ISimpleIdMapperBuilder mapper;

            if (idMapper != null)
            {
                // Multiple id
                throw new MappingException("Multi id mapping isn't (wasn't?) available in NH Core");
            }
            if (idProp.IsComposite)
            {
                // Embedded id
                var idComponent = (Component)idProp.Value;

                mapper = new EmbeddedIdMapper(getIdPropertyData(idProp), idComponent.ComponentClass);
                addIdProperties(relIdMapping, idComponent.PropertyIterator, mapper, false);

                // null mapper - the mapping where already added the first time, now we only want to generate the xml
                addIdProperties(origIdMapping, idComponent.PropertyIterator, null, true);
            }
            else
            {
                // Single id
                mapper = new SingleIdMapper();

                // Last but one parameter: ids are always insertable
                _mainGenerator.BasicMetadataGenerator.AddBasic(relIdMapping,
                                                               getIdPersistentPropertyAuditingData(idProp),
                                                               idProp.Value, mapper, true, false);

                // null mapper - the mapping where already added the first time, now we only want to generate the xml
                _mainGenerator.BasicMetadataGenerator.AddBasic(origIdMapping,
                                                               getIdPersistentPropertyAuditingData(idProp),
                                                               idProp.Value, null, true, true);
            }

            // Adding a relation to the revision entity (effectively: the "revision number" property)
            _mainGenerator.AddRevisionInfoRelation(origIdMapping);

            return(new IdMappingData(mapper, origIdMapping, relIdMapping));
        }
Esempio n. 15
0
        /// <summary>
        /// Adds mapping of the id of a related entity to the given xml mapping, prefixing the id with the given prefix.
        /// </summary>
        /// <param name="xmlMapping">Mapping, to which to add the xml.</param>
        /// <param name="prefix">Prefix for the names of properties which will be prepended to properties that form the id.</param>
        /// <param name="columnNames">Column names that will be used for properties that form the id.</param>
        /// <param name="relatedIdMapping">Id mapping data of the related entity.</param>
        private static void addRelatedToXmlMapping(XElement xmlMapping, string prefix,
                                                   IEnumerable <string> columnNames,
                                                   IdMappingData relatedIdMapping)
        {
            var properties = new XElement(relatedIdMapping.XmlRelationMapping);

            MetadataTools.PrefixNamesInPropertyElement(properties, prefix, columnNames, true, true, null);
            foreach (var idProperty in properties.Elements())
            {
                xmlMapping.Add(idProperty);
            }
        }
Esempio n. 16
0
        //@SuppressWarnings({"unchecked"})
        public void AddToOne(XmlElement parent, PropertyAuditingData propertyAuditingData, IValue value,
                             ICompositeMapperBuilder mapper, String entityName, bool insertable)
        {
            String referencedEntityName = ((ToOne)value).ReferencedEntityName;

            IdMappingData idMapping = mainGenerator.GetReferencedIdMappingData(entityName, referencedEntityName,
                                                                               propertyAuditingData, true);

            String lastPropertyPrefix = MappingTools.createToOneRelationPrefix(propertyAuditingData.Name);

            // Generating the id mapper for the relation
            IIdMapper relMapper = idMapping.IdMapper.PrefixMappedProperties(lastPropertyPrefix);

            // Storing information about this relation
            mainGenerator.EntitiesConfigurations[entityName].AddToOneRelation(
                propertyAuditingData.Name, referencedEntityName, relMapper, insertable);

            // If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
            // that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
            // When that's the case and the user specified to store this relation without a middle table (using
            // @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to
            // the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
            // to the entity that did involve the relation, it's the responsibility of the collection side to store the
            // proper data.
            bool nonInsertableFake;

            if (!insertable && propertyAuditingData.ForceInsertable)
            {
                nonInsertableFake = true;
                insertable        = true;
            }
            else
            {
                nonInsertableFake = false;
            }


            // Adding an element to the mapping corresponding to the references entity id's
            // Use OwnerDocument.ImportNode() instead of XmlNode.Clone();
            XmlElement properties = (XmlElement)parent.OwnerDocument.ImportNode(idMapping.XmlRelationMapping, true);

            properties.SetAttribute("name", propertyAuditingData.Name);

            MetadataTools.PrefixNamesInPropertyElement(properties, lastPropertyPrefix,
                                                       MetadataTools.GetColumnNameEnumerator((IEnumerator <ISelectable>)value.ColumnIterator.GetEnumerator()), false, insertable);
            parent.AppendChild(properties);


            // Adding mapper for the id
            PropertyData propertyData = propertyAuditingData.getPropertyData();

            mapper.AddComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake));
        }
Esempio n. 17
0
        /**
         * Adds mapping of the id of a related entity to the given xml mapping, prefixing the id with the given prefix.
         * @param xmlMapping Mapping, to which to add the xml.
         * @param prefix Prefix for the names of properties which will be prepended to properties that form the id.
         * @param columnNameIterator Iterator over the column names that will be used for properties that form the id.
         * @param relatedIdMapping Id mapping data of the related entity.
         */
        private void AddRelatedToXmlMapping(XmlElement xmlMapping, String prefix,
                                            MetadataTools.ColumnNameEnumerator columnNameIterator,
                                            IdMappingData relatedIdMapping)
        {
            XmlElement properties = (XmlElement)relatedIdMapping.XmlRelationMapping.Clone();

            MetadataTools.PrefixNamesInPropertyElement(properties, prefix, columnNameIterator, true, true);
            foreach (XmlElement idProperty in (System.Collections.Generic.IList <XmlElement>)properties.ChildNodes)
            {
                xmlMapping.AppendChild((XmlElement)idProperty.Clone());
            }
        }
Esempio n. 18
0
        public void AddRevisionType(XElement anyMapping, XElement anyMappingEnd)
        {
            var partOfId        = anyMapping != anyMappingEnd;
            var revTypeProperty = MetadataTools.AddProperty(anyMapping, VerEntCfg.RevisionTypePropName,
                                                            typeof(RevisionTypeType).AssemblyQualifiedName, true, partOfId, null);

            if (!partOfId)
            {
                revTypeProperty.Add(new XAttribute("not-null", "true"));
            }
            GlobalCfg.AuditStrategy.AddExtraRevisionMapping(anyMappingEnd, revisionInfoRelationMapping);
        }
        private static void addSimpleValue(XElement parent, PropertyAuditingData propertyAuditingData,
                                           IValue value, ISimpleMapperBuilder mapper, bool insertable, bool key)
        {
            if (parent != null)
            {
                var propMapping = MetadataTools.AddProperty(parent, propertyAuditingData.Name,
                                                            value.Type.Name, propertyAuditingData.ForceInsertable || insertable, key, propertyAuditingData.AccessType);
                MetadataTools.AddColumns(propMapping, value.ColumnIterator.OfType <Column>());
            }

            // A null mapper means that we only want to add xml mappings
            mapper?.Add(propertyAuditingData.GetPropertyData());
        }
Esempio n. 20
0
        private void AddSimpleValue(XmlElement parent, PropertyAuditingData propertyAuditingData,
                                    IValue value, ISimpleMapperBuilder mapper, bool insertable, bool key)
        {
            if (parent != null)
            {
                XmlElement prop_mapping = MetadataTools.AddProperty(parent, propertyAuditingData.Name,
                                                                    value.Type.Name, propertyAuditingData.ForceInsertable || insertable, key);
                MetadataTools.AddColumns(prop_mapping, (IEnumerator <ISelectable>)value.ColumnIterator.GetEnumerator());
            }

            // A null mapper means that we only want to add xml mappings
            if (mapper != null)
            {
                mapper.Add(propertyAuditingData.getPropertyData());
            }
        }
Esempio n. 21
0
 private static string searchMappedBy(PersistentClass referencedClass, Mapping.Collection collectionValue)
 {
     foreach (var property in referencedClass.PropertyIterator)
     {
         if (MetadataTools.IsNoneAccess(property.PropertyAccessorName))
         {
             continue;
         }
         //should probably not care if order is same...
         if (property.Value.ColumnIterator.SequenceEqual(collectionValue.Key.ColumnIterator))
         {
             return(property.Name);
         }
     }
     return(null);
 }
        //@SuppressWarnings({"unchecked"})
        private Triple<XmlElement, IExtendedPropertyMapper, String> GenerateMappingData(
                PersistentClass pc, EntityXmlMappingData xmlMappingData, AuditTableData auditTableData,
                IdMappingData idMapper)
        {
            bool hasDiscriminator = pc.Discriminator != null;

            XmlElement class_mapping = MetadataTools.CreateEntity(xmlMappingData.MainXmlMapping, auditTableData,
                    hasDiscriminator ? pc.DiscriminatorValue : null);
            IExtendedPropertyMapper propertyMapper = new MultiPropertyMapper();

            // Checking if there is a discriminator column
            if (hasDiscriminator)
            {
                XmlElement discriminator_element = class_mapping.OwnerDocument.CreateElement("discriminator");
                class_mapping.AppendChild(discriminator_element);
                MetadataTools.AddColumns(discriminator_element, (IEnumerator<ISelectable>)pc.Discriminator.ColumnIterator.GetEnumerator());
                discriminator_element.SetAttribute("type", pc.Discriminator.Type.Name);
            }

            InheritanceType.Type parentInheritance = InheritanceType.GetForParent(pc);
            switch (parentInheritance)
            {
                case InheritanceType.Type.NONE:
                    break;

                case InheritanceType.Type.SINGLE:
                    AddSingleInheritancePersisterHack(class_mapping);
                    break;

                case InheritanceType.Type.JOINED:
                    AddJoinedInheritancePersisterHack(class_mapping);
                    break;

                case InheritanceType.Type.TABLE_PER_CLASS:
                    AddTablePerClassInheritancePersisterHack(class_mapping);
                    break;
            }

            // Adding the id mapping
            XmlNode xmlMp = class_mapping.OwnerDocument.ImportNode(idMapper.XmlMapping,true);
            class_mapping.AppendChild(xmlMp);

            // Adding the "revision type" property
            AddRevisionType(class_mapping);

            return Triple<XmlElement, IExtendedPropertyMapper, string>.Make<XmlElement, IExtendedPropertyMapper, string>(class_mapping, propertyMapper, null);
        }
        //@SuppressWarnings({"unchecked"})
        private void CreateJoins(PersistentClass pc, XmlElement parent, ClassAuditingData auditingData)
        {
            IEnumerator<Join> joins = pc.JoinIterator.GetEnumerator();

            IDictionary<Join, XmlElement> JoinElements = new Dictionary<Join, XmlElement>();
            entitiesJoins.Add(pc.EntityName, JoinElements);

            while (joins.MoveNext())
            {
                Join join = joins.Current;

                // Checking if all of the join properties are audited
                if (!CheckPropertiesAudited(join.PropertyIterator.GetEnumerator(), auditingData))
                {
                    continue;
                }

                // Determining the table name. If there is no entry in the dictionary, just constructing the table name
                // as if it was an entity (by appending/prepending configured strings).
                String originalTableName = join.Table.Name;
                String auditTableName = auditingData.SecondaryTableDictionary[originalTableName];
                if (auditTableName == null)
                {
                    auditTableName = VerEntCfg.GetAuditEntityName(originalTableName);
                }

                String schema = GetSchema(auditingData.AuditTable.schema, join.Table);
                String catalog = GetCatalog(auditingData.AuditTable.catalog, join.Table);

                XmlElement joinElement = MetadataTools.CreateJoin(parent, auditTableName, schema, catalog);
                JoinElements.Add(join, joinElement);

                XmlElement joinKey = joinElement.OwnerDocument.CreateElement("key");
                joinElement.AppendChild(joinKey);
                MetadataTools.AddColumns(joinKey, (IEnumerator<ISelectable>)join.Key.ColumnIterator.GetEnumerator());
                MetadataTools.AddColumn(joinKey, VerEntCfg.RevisionFieldName, -1, 0, 0, null);
            }
        }
Esempio n. 24
0
        private void AddCustomValue(XmlElement parent, PropertyAuditingData propertyAuditingData,
                                    IValue value, ISimpleMapperBuilder mapper, bool insertable, bool key)
        {
            if (parent != null)
            {
                XmlElement prop_mapping = MetadataTools.AddProperty(parent, propertyAuditingData.Name,
                                                                    null, insertable, key);

                //CustomType propertyType = (CustomType) value.getType();

                XmlElement type_mapping = parent.OwnerDocument.CreateElement("type");
                prop_mapping.AppendChild(type_mapping);
                type_mapping.SetAttribute("name", value.GetType().Name);

                if (value is SimpleValue)
                {
                    IDictionary <string, string> typeParameters = ((SimpleValue)value).TypeParameters;
                    if (typeParameters != null)
                    {
                        foreach (KeyValuePair <string, string> paramKeyValue in typeParameters)
                        {
                            XmlElement type_param = parent.OwnerDocument.CreateElement("param");
                            type_param.SetAttribute("name", (String)paramKeyValue.Key);
                            type_param["name"].Value = paramKeyValue.Value;
                        }
                    }
                }

                MetadataTools.AddColumns(prop_mapping, (IEnumerator <ISelectable>)value.ColumnIterator);
            }

            if (mapper != null)
            {
                mapper.Add(propertyAuditingData.getPropertyData());
            }
        }
 /**
  * Adds mapping of the id of a related entity to the given xml mapping, prefixing the id with the given prefix.
  * @param xmlMapping Mapping, to which to add the xml.
  * @param prefix Prefix for the names of properties which will be prepended to properties that form the id.
  * @param columnNameIterator Iterator over the column names that will be used for properties that form the id.
  * @param relatedIdMapping Id mapping data of the related entity.
  */
 private void AddRelatedToXmlMapping(XmlElement xmlMapping, String prefix,
     MetadataTools.ColumnNameEnumerator columnNameIterator,
     IdMappingData relatedIdMapping)
 {
     XmlElement properties = (XmlElement) relatedIdMapping.XmlRelationMapping.Clone();
     MetadataTools.PrefixNamesInPropertyElement(properties, prefix, columnNameIterator, true, true);
     foreach (XmlElement idProperty in (System.Collections.Generic.IList<XmlElement>) properties.ChildNodes) {
         xmlMapping.AppendChild((XmlElement) idProperty.Clone());
     }
 }
Esempio n. 26
0
        public void GenerateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
                                      EntityXmlMappingData xmlMappingData, bool isAudited)
        {
            var schema  = GetSchema(auditingData.AuditTable.Schema, pc.Table);
            var catalog = GetCatalog(auditingData.AuditTable.Catalog, pc.Table);
            Func <System.Type, object> factory = auditingData.Factory.Factory.Instantiate;

            var entityName = pc.EntityName;

            if (!isAudited)
            {
                var _idMapper = idMetadataGenerator.AddId(pc);

                if (_idMapper == null)
                {
                    // Unsupported id mapping, e.g. key-many-to-one. If the entity is used in auditing, an exception
                    // will be thrown later on.
                    if (log.IsDebugEnabled)
                    {
                        log.DebugFormat("Unable to create auditing id mapping for entity {0}" +
                                        ", because of an unsupported Hibernate id mapping (e.g. key-many-to-one).", entityName);
                    }
                    return;
                }

                //ORIG:
                //IExtendedPropertyMapper propertyMapper = null;
                //String parentEntityName = null;
                var _entityCfg = new EntityConfiguration(entityName, pc.ClassName, _idMapper, null, null, factory);
                NotAuditedEntitiesConfigurations.Add(entityName, _entityCfg);
                return;
            }

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Generating first-pass auditing mapping for entity {0}.", entityName);
            }

            var auditEntityName = VerEntCfg.GetAuditEntityName(entityName);
            var auditTableName  = VerEntCfg.AuditTableName(entityName, pc);

            // Registering the audit entity name, now that it is known
            AuditEntityNameRegister.Register(auditEntityName);

            var auditTableData = new AuditTableData(auditEntityName, auditTableName, schema, catalog);

            // Generating a mapping for the id
            var idMapper = idMetadataGenerator.AddId(pc);

            if (idMapper == null)
            {
                throw new AuditException("Id mapping for type " + pc.ClassName +
                                         " is currently not supported in Envers. If you need composite-id, use 'Components as composite identifiers'.");
            }

            var inheritanceType = pc.GetInheritanceType();

            // These properties will be read from the mapping data

            Tuple <XElement, IExtendedPropertyMapper, string> mappingData;

            // Reading the mapping data depending on inheritance type (if any)
            switch (inheritanceType)
            {
            case InheritanceType.None:
                mappingData = generateMappingData(pc, xmlMappingData, auditTableData, idMapper);
                break;

            case InheritanceType.Single:
                auditTableData = new AuditTableData(auditEntityName, null, schema, catalog);
                mappingData    = generateInheritanceMappingData(pc, xmlMappingData, auditTableData, "subclass");
                break;

            case InheritanceType.Joined:
                mappingData = generateInheritanceMappingData(pc, xmlMappingData, auditTableData, "joined-subclass");

                // Adding the "key" element with all id columns...
                var keyMapping = new XElement(MetadataTools.CreateElementName("key"));
                mappingData.Item1.Add(keyMapping);
                MetadataTools.AddColumns(keyMapping, pc.Table.PrimaryKey.ColumnIterator);

                // ... and the revision number column, read from the revision info relation mapping.
                keyMapping.Add(cloneAndSetupRevisionInfoRelationMapping().Element(MetadataTools.CreateElementName("column")));
                break;

            case InheritanceType.TablePerClass:
                mappingData = generateInheritanceMappingData(pc, xmlMappingData, auditTableData, "union-subclass");

                break;

            default:
                throw new AssertionFailure("AuditMetadataGenerator.GenerateFirstPass: Impossible enum value.");
            }

            var classMapping     = mappingData.Item1;
            var propertyMapper   = mappingData.Item2;
            var parentEntityName = mappingData.Item3;

            xmlMappingData.ClassMapping = classMapping;

            // Mapping unjoined properties
            addProperties(classMapping, pc.UnjoinedPropertyIterator, propertyMapper,
                          auditingData, pc.EntityName, xmlMappingData,
                          true);

            // Creating and mapping joins (first pass)
            createJoins(pc, classMapping, auditingData);
            addJoins(pc, propertyMapper, auditingData, pc.EntityName, xmlMappingData, true);

            // Storing the generated configuration
            var entityCfg = new EntityConfiguration(auditEntityName, pc.ClassName, idMapper,
                                                    propertyMapper, parentEntityName, factory);

            EntitiesConfigurations.Add(pc.EntityName, entityCfg);
        }
        public void AddToOne(XElement parent, PropertyAuditingData propertyAuditingData, IValue value,
                             ICompositeMapperBuilder mapper, string entityName, bool insertable)
        {
            var referencedEntityName = ((ToOne)value).ReferencedEntityName;
            var idMapping            = _mainGenerator.GetReferencedIdMappingData(entityName, referencedEntityName,
                                                                                 propertyAuditingData, true);

            var lastPropertyPrefix = MappingTools.CreateToOneRelationPrefix(propertyAuditingData.Name);

            // Generating the id mapper for the relation
            var relMapper = idMapping.IdMapper.PrefixMappedProperties(lastPropertyPrefix);

            // Storing information about this relation
            _mainGenerator.EntitiesConfigurations[entityName].AddToOneRelation(
                propertyAuditingData.Name, referencedEntityName, relMapper, insertable, MappingTools.IgnoreNotFound(value));

            // If the property isn't insertable, checking if this is not a "fake" bidirectional many-to-one relationship,
            // that is, when the one side owns the relation (and is a collection), and the many side is non insertable.
            // When that's the case and the user specified to store this relation without a middle table (using
            // @AuditMappedBy), we have to make the property insertable for the purposes of Envers. In case of changes to
            // the entity that didn't involve the relation, it's value will then be stored properly. In case of changes
            // to the entity that did involve the relation, it's the responsibility of the collection side to store the
            // proper data.
            bool nonInsertableFake;

            if (!insertable && propertyAuditingData.ForceInsertable)
            {
                nonInsertableFake = true;
                insertable        = true;
            }
            else
            {
                nonInsertableFake = false;
            }


            // Adding an element to the mapping corresponding to the references entity id's
            var properties = new XElement(idMapping.XmlRelationMapping);

            properties.Add(new XAttribute("name", propertyAuditingData.Name));

            MetadataTools.PrefixNamesInPropertyElement(properties, lastPropertyPrefix,
                                                       MetadataTools.GetColumnNameEnumerator(value.ColumnIterator),
                                                       false, insertable, propertyAuditingData.AccessType);

            // Extracting related id properties from properties tag
            var firstJoin = firstJoinElement(parent);

            foreach (var element in properties.Elements())
            {
                if (firstJoin == null)
                {
                    parent.Add(element);
                }
                else
                {
                    firstJoin.AddBeforeSelf(element);
                }
            }

            // Adding mapper for the id
            var propertyData = propertyAuditingData.GetPropertyData();

            mapper.AddComposite(propertyData, new ToOneIdMapper(relMapper, propertyData, referencedEntityName, nonInsertableFake));
        }
 private static XElement firstJoinElement(XElement classElement)
 {
     //do we have to check for other elements than join here?
     return(classElement.Element(MetadataTools.CreateElementName("join")));
 }
Esempio n. 29
0
        private void addWithMiddleTable()
        {
            log.Debug("Adding audit mapping for property {0}. {1}" +
                      ": collection with a join table.", _referencingEntityName, _propertyName);

            // Generating the name of the middle table
            string auditMiddleTableName;
            string auditMiddleEntityName;

            if (!string.IsNullOrEmpty(_propertyAuditingData.JoinTable.TableName))
            {
                auditMiddleTableName  = _propertyAuditingData.JoinTable.TableName;
                auditMiddleEntityName = _propertyAuditingData.JoinTable.TableName;
            }
            else
            {
                // We check how Hibernate maps the collection.
                if (_propertyValue.Element is OneToMany && !_propertyValue.IsInverse)
                {
                    // This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate doesn't use a
                    // middle table for mapping this relation.
                    var referencingPersistentClass = _mainGenerator.Cfg.GetClassMapping(_referencingEntityName);
                    var referencedPersistentClass  = _mainGenerator.Cfg.GetClassMapping(_referencedEntityName);
                    auditMiddleTableName  = _mainGenerator.VerEntCfg.UnidirectionOneToManyTableName(referencingPersistentClass, referencedPersistentClass);
                    auditMiddleEntityName = _mainGenerator.VerEntCfg.GetAuditEntityName(_referencingEntityName, _referencedEntityName);
                }
                else
                {
                    auditMiddleTableName  = _mainGenerator.VerEntCfg.CollectionTableName(_propertyValue);
                    auditMiddleEntityName = _mainGenerator.VerEntCfg.GetAuditEntityName(_propertyValue.CollectionTable.Name);
                }
            }

            log.Debug("Using join table name: {0}", auditMiddleTableName);

            // Generating the XML mapping for the middle entity, only if the relation isn't inverse.
            // If the relation is inverse, will be later checked by comparing middleEntityXml with null.
            XElement middleEntityXml;

            if (!_propertyValue.IsInverse)
            {
                // Generating a unique middle entity name
                auditMiddleEntityName = _mainGenerator.AuditEntityNameRegister.CreateUnique(auditMiddleEntityName);

                // Registering the generated name
                _mainGenerator.AuditEntityNameRegister.Register(auditMiddleEntityName);

                middleEntityXml = createMiddleEntityXml(auditMiddleTableName, auditMiddleEntityName, _propertyValue.Where);
            }
            else
            {
                middleEntityXml = null;
            }

            // ******
            // Generating the mapping for the referencing entity (it must be an entity).
            // ******
            // Getting the id-mapping data of the referencing entity (the entity that "owns" this collection).
            var referencingIdMapping = _referencingEntityConfiguration.IdMappingData;

            // Only valid for an inverse relation; null otherwise.
            string mappedBy;

            // The referencing prefix is always for a related entity. So it has always the "_" at the end added.
            string referencingPrefixRelated;
            string referencedPrefix;

            if (_propertyValue.IsInverse)
            {
                // If the relation is inverse, then referencedEntityName is not null.
                mappedBy = getMappedBy(_propertyValue.CollectionTable, _mainGenerator.Cfg.GetClassMapping(_referencedEntityName));

                referencingPrefixRelated = mappedBy + "_";
                referencedPrefix         = StringTools.GetLastComponent(_referencedEntityName);
            }
            else
            {
                mappedBy = null;

                referencingPrefixRelated = StringTools.GetLastComponent(_referencingEntityName) + "_";
                referencedPrefix         = _referencedEntityName == null ? "element" : _propertyName;
            }

            // Storing the id data of the referencing entity: original mapper, prefixed mapper and entity name.
            var referencingIdData = createMiddleIdData(referencingIdMapping, referencingPrefixRelated, _referencingEntityName);

            // Creating a query generator builder, to which additional id data will be added, in case this collection
            // references some entities (either from the element or index). At the end, this will be used to build
            // a query generator to read the raw data collection from the middle table.
            var queryGeneratorBuilder = new QueryGeneratorBuilder(_mainGenerator.VerEntCfg, _mainGenerator.GlobalCfg.AuditStrategy, referencingIdData, auditMiddleEntityName, isEmbeddableElementType());

            // Adding the XML mapping for the referencing entity, if the relation isn't inverse.
            if (middleEntityXml != null)
            {
                // Adding related-entity (in this case: the referencing's entity id) id mapping to the xml.
                addRelatedToXmlMapping(middleEntityXml, referencingPrefixRelated,
                                       MetadataTools.GetColumnNameEnumerator(_propertyValue.Key.ColumnIterator),
                                       referencingIdMapping);
            }

            // ******
            // Generating the element mapping.
            // ******
            var elementComponentData = addValueToMiddleTable(_propertyValue.Element, middleEntityXml,
                                                             queryGeneratorBuilder, referencedPrefix, _propertyAuditingData.JoinTable.InverseJoinColumns);

            // ******
            // Generating the index mapping, if an index exists.
            // ******
            var indexComponentData = addIndex(middleEntityXml, queryGeneratorBuilder);

            // ******
            // Generating the property mapper.
            // ******
            // Building the query generator.
            var queryGenerator = queryGeneratorBuilder.Build(new Collection <MiddleComponentData> {
                elementComponentData, indexComponentData
            });

            // Creating common data
            var commonCollectionMapperData = new CommonCollectionMapperData(
                _mainGenerator.VerEntCfg, auditMiddleEntityName,
                _propertyAuditingData.GetPropertyData(),
                referencingIdData, queryGenerator);

            // Checking the type of the collection and adding an appropriate mapper.
            addMapper(commonCollectionMapperData, elementComponentData, indexComponentData);

            // ******
            // Storing information about this relation.
            // ******
            storeMiddleEntityRelationInformation(mappedBy);
        }
Esempio n. 30
0
        /// <summary>
        /// Add value to middle table
        /// </summary>
        /// <param name="value">Value, which should be mapped to the middle-table, either as a relation to another entity, or as a simple value.</param>
        /// <param name="xmlMapping">If not <code>null</code>, xml mapping for this value is added to this element.</param>
        /// <param name="queryGeneratorBuilder">In case <code>value</code> is a relation to another entity, information about it should be added to the given.</param>
        /// <param name="prefix">Prefix for proeprty names of related entities identifiers.</param>
        /// <param name="joinColumns">Names of columns to use in the xml mapping, if this array isn't null and has any elements.</param>
        /// <returns>Data for mapping this component.</returns>
        private MiddleComponentData addValueToMiddleTable(IValue value, XElement xmlMapping,
                                                          QueryGeneratorBuilder queryGeneratorBuilder,
                                                          string prefix, string[] joinColumns)
        {
            var type = value.Type;

            if (type is ManyToOneType)
            {
                var prefixRelated        = prefix + "_";
                var referencedEntityName = MappingTools.ReferencedEntityName(value);

                var referencedIdMapping = _mainGenerator.GetReferencedIdMappingData(_referencingEntityName,
                                                                                    referencedEntityName, _propertyAuditingData, true);

                // Adding related-entity (in this case: the referenced entities id) id mapping to the xml only if the
                // relation isn't inverse (so when <code>xmlMapping</code> is not null).
                if (xmlMapping != null)
                {
                    addRelatedToXmlMapping(xmlMapping, prefixRelated,
                                           joinColumns != null && joinColumns.Length > 0
                                                                        ? joinColumns
                                                                        : MetadataTools.GetColumnNameEnumerator(value.ColumnIterator),
                                           referencedIdMapping);
                }

                // Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
                var referencedIdData = createMiddleIdData(referencedIdMapping,
                                                          prefixRelated, referencedEntityName);
                // And adding it to the generator builder.
                queryGeneratorBuilder.AddRelation(referencedIdData);

                return(new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData),
                                               queryGeneratorBuilder.CurrentIndex));
            }
            else if (type is ComponentType)
            {
                //collection of embaddable elements
                var component        = (Component)value;
                var componentMapper  = new MiddleEmbeddableComponentMapper(new MultiPropertyMapper(), component.ComponentClassName);
                var parentXmlMapping = xmlMapping.Parent;

                var auditData = new ComponentAuditingData();

                new ComponentAuditedPropertiesReader(_metaDataStore,
                                                     new AuditedPropertiesReader.ComponentPropertiesSource(component),
                                                     auditData, _mainGenerator.GlobalCfg, "").Read();

                // Emulating first pass.
                foreach (var auditedPropertyName in auditData.PropertyNames)
                {
                    var nestedAuditingData = auditData.GetPropertyAuditingData(auditedPropertyName);
                    _mainGenerator.AddValue(parentXmlMapping, component.GetProperty(auditedPropertyName).Value, componentMapper, prefix, _xmlMappingData, nestedAuditingData, true, true, true);
                }

                // Emulating second pass so that the relations can be mapped too.
                foreach (var auditedPropertyName in auditData.PropertyNames)
                {
                    var nestedAuditingData = auditData.GetPropertyAuditingData(auditedPropertyName);
                    _mainGenerator.AddValue(parentXmlMapping, component.GetProperty(auditedPropertyName).Value, componentMapper, _referencingEntityName, _xmlMappingData, nestedAuditingData, true, false, true);
                }

                // Add an additional column holding a number to make each entry unique within the set.
                // Embeddable properties may contain null values, so cannot be stored within composite primary key.
                if (_propertyValue.IsSet)
                {
                    var setOrdinalPropertyName = _mainGenerator.VerEntCfg.EmbeddableSetOrdinalPropertyName;
                    var ordinalProperty        = MetadataTools.AddProperty(xmlMapping, setOrdinalPropertyName, "int", true, true, null);
                    MetadataTools.AddColumn(ordinalProperty, setOrdinalPropertyName, -1, -1, -1, null, false);
                }
                return(new MiddleComponentData(componentMapper, 0));
            }
            // Last but one parameter: collection components are always insertable
            var mapped = _mainGenerator.BasicMetadataGenerator.AddBasic(xmlMapping,
                                                                        new PropertyAuditingData(prefix, "field"),
                                                                        value, null, true, true);

            if (mapped)
            {
                // Simple values are always stored in the first item of the array returned by the query generator.
                return(new MiddleComponentData(new MiddleSimpleComponentMapper(_mainGenerator.VerEntCfg, prefix), 0));
            }
            _mainGenerator.ThrowUnsupportedTypeException(type, _referencingEntityName, _propertyName);
            // Impossible to get here.
            throw new AssertionFailure();
        }
        //@SuppressWarnings({"unchecked"})
        public void GenerateFirstPass(PersistentClass pc, ClassAuditingData auditingData,
                                      EntityXmlMappingData xmlMappingData, bool isAudited)
        {
            String schema = GetSchema(auditingData.AuditTable.schema, pc.Table);
            String catalog = GetCatalog(auditingData.AuditTable.catalog, pc.Table);

            String entityName = pc.EntityName;
            if (!isAudited)
            {
                IdMappingData _idMapper = idMetadataGenerator.AddId(pc);

                if (_idMapper == null)
                {
                    // Unsupported id mapping, e.g. key-many-to-one. If the entity is used in auditing, an exception
                    // will be thrown later on.
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Unable to create auditing id mapping for entity " + entityName +
                            ", because of an unsupported Hibernate id mapping (e.g. key-many-to-one).");
                    }
                    return;
                }

                //ORIG:
                //IExtendedPropertyMapper propertyMapper = null;
                //String parentEntityName = null;
                EntityConfiguration _entityCfg = new EntityConfiguration(entityName, _idMapper, null,
                        null);
                NotAuditedEntitiesConfigurations.Add(entityName, _entityCfg);
                return;
            }

            if (log.IsDebugEnabled)
            {
                log.Debug("Generating first-pass auditing mapping for entity " + entityName + ".");
            }

            String auditEntityName = VerEntCfg.GetAuditEntityName(entityName);
            String auditTableName = VerEntCfg.GetAuditTableName(entityName, pc.Table.Name);

            // Registering the audit entity name, now that it is known
            AuditEntityNameRegister.register(auditEntityName);

            AuditTableData auditTableData = new AuditTableData(auditEntityName, auditTableName, schema, catalog);

            // Generating a mapping for the id
            IdMappingData idMapper = idMetadataGenerator.AddId(pc);

            InheritanceType.Type inheritanceType = InheritanceType.GetForChild(pc);

            // These properties will be read from the mapping data
            XmlElement class_mapping;
            IExtendedPropertyMapper propertyMapper;
            String parentEntityName;

            Triple<XmlElement, IExtendedPropertyMapper, String> mappingData;

            // Reading the mapping data depending on inheritance type (if any)
            switch (inheritanceType)
            {
                case InheritanceType.Type.NONE:
                    mappingData = GenerateMappingData(pc, xmlMappingData, auditTableData, idMapper);
                    break;

                case InheritanceType.Type.SINGLE:
                    mappingData = GenerateInheritanceMappingData(pc, xmlMappingData, auditTableData, "subclass");
                    break;

                case InheritanceType.Type.JOINED:
                    mappingData = GenerateInheritanceMappingData(pc, xmlMappingData, auditTableData, "joined-subclass");

                    AddJoinedInheritancePersisterHack(mappingData.First);

                    // Adding the "key" element with all id columns...
                    XmlElement keyMapping = mappingData.First.OwnerDocument.CreateElement("key");
                    mappingData.First.AppendChild(keyMapping);
                    MetadataTools.AddColumns(keyMapping, (IEnumerator<ISelectable>)pc.Table.PrimaryKey.ColumnIterator.GetEnumerator());

                    // ... and the revision number column, read from the revision info relation mapping.
                    keyMapping.AppendChild((XmlElement)CloneAndSetupRevisionInfoRelationMapping(keyMapping.OwnerDocument).GetElementsByTagName("column")[0].Clone());
                    break;

                case InheritanceType.Type.TABLE_PER_CLASS:
                    mappingData = GenerateInheritanceMappingData(pc, xmlMappingData, auditTableData, "union-subclass");

                    AddTablePerClassInheritancePersisterHack(mappingData.First);

                    break;

                default:
                    throw new AssertionFailure("Envers.NET: AuditMetadataGenerator.GenerateFirstPass: Impossible enum value.");
            }

            class_mapping = mappingData.First;
            propertyMapper = mappingData.Second;
            parentEntityName = mappingData.Third;

            xmlMappingData.ClassMapping = class_mapping;

            // Mapping unjoined properties
            AddProperties(class_mapping, (IEnumerator<Property>)pc.UnjoinedPropertyIterator.GetEnumerator(), propertyMapper,
                    auditingData, pc.EntityName, xmlMappingData,
                    true);

            // Creating and mapping joins (first pass)
            CreateJoins(pc, class_mapping, auditingData);
            AddJoins(pc, propertyMapper, auditingData, pc.EntityName, xmlMappingData, true);

            // Storing the generated configuration
            EntityConfiguration entityCfg = new EntityConfiguration(auditEntityName, idMapper,
                    propertyMapper, parentEntityName);
            EntitiesConfigurations.Add(pc.EntityName, entityCfg);
        }