/** * * @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(); } } }
private MiddleComponentData addIndex(XElement middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) { var indexedValue = _propertyValue as IndexedCollection; if (indexedValue != null) { var idMatch = false; Property referencedProperty = null; PersistentClass refPc = null; if (_referencedEntityName != null) { refPc = _mainGenerator.Cfg.GetClassMapping(_referencedEntityName); } if (refPc != null) { idMatch = MappingTools.SameColumns(refPc.IdentifierProperty.ColumnIterator, indexedValue.Index.ColumnIterator); foreach (var propertyRef in refPc.PropertyIterator) { if (MappingTools.SameColumns(propertyRef.ColumnIterator, indexedValue.Index.ColumnIterator)) { referencedProperty = propertyRef; break; } } } if (!idMatch && referencedProperty == null) { return(addValueToMiddleTable(indexedValue.Index, middleEntityXml, queryGeneratorBuilder, "mapkey", null)); } var currentIndex = queryGeneratorBuilder?.CurrentIndex ?? 0; if (idMatch) { // The key of the map is the id of the entity. var referencedIdMapping = _mainGenerator.EntitiesConfigurations[_referencedEntityName].IdMappingData; return(new MiddleComponentData(new MiddleMapKeyIdComponentMapper(_mainGenerator.VerEntCfg, referencedIdMapping.IdMapper), currentIndex)); } if (indexedValue is Map) { // The key of the map is a property of the entity. return(new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(referencedProperty.Name, referencedProperty.PropertyAccessorName), currentIndex)); } //bidirectional list // The key of the map is a property of the entity. return(new MiddleComponentData(new MiddleStraightComponentMapper(referencedProperty.Name), currentIndex)); } // No index - creating a dummy mapper. return(new MiddleComponentData(new MiddleDummyComponentMapper(), 0)); }
private MiddleComponentData AddIndex(XmlElement middleEntityXml, QueryGeneratorBuilder queryGeneratorBuilder) { if (propertyValue is IndexedCollection) { IndexedCollection indexedValue = (IndexedCollection)propertyValue; String mapKey = propertyAuditingData.MapKey; if (mapKey == null) { // This entity doesn't specify a javax.persistence.MapKey. Mapping it to the middle entity. return(AddValueToMiddleTable(indexedValue.Index, middleEntityXml, queryGeneratorBuilder, "mapkey", null)); } else { IdMappingData referencedIdMapping = mainGenerator.EntitiesConfigurations[referencedEntityName].IdMappingData; int currentIndex = queryGeneratorBuilder == null ? 0 : queryGeneratorBuilder.CurrentIndex; if ("".Equals(mapKey)) { // The key of the map is the id of the entity. return(new MiddleComponentData(new MiddleMapKeyIdComponentMapper(mainGenerator.VerEntCfg, referencedIdMapping.IdMapper), currentIndex)); } else { // The key of the map is a property of the entity. return(new MiddleComponentData(new MiddleMapKeyPropertyComponentMapper(mapKey, propertyAuditingData.AccessType), currentIndex)); } } } else { // No index - creating a dummy mapper. return(new MiddleComponentData(new MiddleDummyComponentMapper(), 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(); }
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); }
private void AddWithMiddleTable() { log.Debug("Adding audit mapping for property " + referencingEntityName + "." + propertyName + ": collection with a join table."); // Generating the name of the middle table String auditMiddleTableName; String auditMiddleEntityName; if (!String.IsNullOrEmpty(propertyAuditingData.JoinTable.Name)) { auditMiddleTableName = propertyAuditingData.JoinTable.Name; auditMiddleEntityName = propertyAuditingData.JoinTable.Name; } else { String middleTableName = GetMiddleTableName(propertyValue, referencingEntityName); auditMiddleTableName = mainGenerator.VerEntCfg.GetAuditTableName(null, middleTableName); auditMiddleEntityName = mainGenerator.VerEntCfg.GetAuditEntityName(middleTableName); } log.Debug("Using join table name: " + 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. XmlElement 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). IdMappingData 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. MiddleIdData 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. QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.GlobalCfg, mainGenerator.VerEntCfg, referencingIdData, auditMiddleEntityName); // 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.GetEnumerator()), referencingIdMapping); } // ****** // Generating the element mapping. // ****** MiddleComponentData elementComponentData = AddValueToMiddleTable(propertyValue.Element, middleEntityXml, queryGeneratorBuilder, referencedPrefix, propertyAuditingData.JoinTable.InverseJoinColumns); // ****** // Generating the index mapping, if an index exists. // ****** MiddleComponentData indexComponentData = AddIndex(middleEntityXml, queryGeneratorBuilder); // ****** // Generating the property mapper. // ****** // Building the query generator. IRelationQueryGenerator queryGenerator = queryGeneratorBuilder.Build(new Collection <MiddleComponentData> { elementComponentData, indexComponentData }); // Creating common data CommonCollectionMapperData 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); }