use of org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData in project hibernate-orm by hibernate.
the class CollectionMetadataGenerator method addValueToMiddleTable.
/**
* @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(Value value, Element xmlMapping, QueryGeneratorBuilder queryGeneratorBuilder, String prefix, JoinColumn[] joinColumns, boolean key) {
final Type type = value.getType();
if (type instanceof ManyToOneType) {
final String prefixRelated = prefix + "_";
final String referencedEntityName = MappingTools.getReferencedEntityName(value);
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(referencingEntityName, referencedEntityName, propertyAuditingData, true);
// relation isn't inverse (so when <code>xmlMapping</code> is not null).
if (xmlMapping != null) {
addRelatedToXmlMapping(xmlMapping, prefixRelated, joinColumns != null && joinColumns.length > 0 ? MetadataTools.getColumnNameIterator(joinColumns) : MetadataTools.getColumnNameIterator(value.getColumnIterator()), referencedIdMapping);
}
// Storing the id data of the referenced entity: original mapper, prefixed mapper and entity name.
final MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping, prefixRelated, referencedEntityName);
// And adding it to the generator builder.
queryGeneratorBuilder.addRelation(referencedIdData);
return new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData), queryGeneratorBuilder.getCurrentIndex());
} else if (type instanceof ComponentType) {
// Collection of embeddable elements.
final Component component = (Component) value;
final Class componentClass = ReflectionTools.loadClass(component.getComponentClassName(), mainGenerator.getClassLoaderService());
final MiddleEmbeddableComponentMapper componentMapper = new MiddleEmbeddableComponentMapper(new MultiPropertyMapper(), componentClass);
final Element parentXmlMapping = xmlMapping.getParent();
final ComponentAuditingData auditData = new ComponentAuditingData();
final ReflectionManager reflectionManager = mainGenerator.getMetadata().getMetadataBuildingOptions().getReflectionManager();
new ComponentAuditedPropertiesReader(ModificationStore.FULL, new AuditedPropertiesReader.ComponentPropertiesSource(reflectionManager, component), auditData, mainGenerator.getGlobalCfg(), reflectionManager, "").read();
// Emulating first pass.
for (String auditedPropertyName : auditData.getPropertyNames()) {
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData(auditedPropertyName);
mainGenerator.addValue(parentXmlMapping, component.getProperty(auditedPropertyName).getValue(), componentMapper, prefix, xmlMappingData, nestedAuditingData, true, true, true);
}
// Emulating second pass so that the relations can be mapped too.
for (String auditedPropertyName : auditData.getPropertyNames()) {
final PropertyAuditingData nestedAuditingData = auditData.getPropertyAuditingData(auditedPropertyName);
mainGenerator.addValue(parentXmlMapping, component.getProperty(auditedPropertyName).getValue(), componentMapper, referencingEntityName, xmlMappingData, nestedAuditingData, true, false, true);
}
// Embeddable properties may contain null values, so cannot be stored within composite primary key.
if (propertyValue.isSet()) {
final String setOrdinalPropertyName = mainGenerator.getVerEntCfg().getEmbeddableSetOrdinalPropertyName();
final Element ordinalProperty = MetadataTools.addProperty(xmlMapping, setOrdinalPropertyName, "integer", true, true);
MetadataTools.addColumn(ordinalProperty, setOrdinalPropertyName, null, null, null, null, null, null, false);
}
return new MiddleComponentData(componentMapper, 0);
} else {
// Last but one parameter: collection components are always insertable
final boolean mapped = mainGenerator.getBasicMetadataGenerator().addBasic(key ? xmlMapping : xmlMapping.getParent(), new PropertyAuditingData(prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false), value, null, true, key);
if (mapped && key) {
// Simple values are always stored in the first item of the array returned by the query generator.
return new MiddleComponentData(new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
} else if (mapped && !key) {
// when mapped but not part of the key, its stored as a dummy mapper??
return new MiddleComponentData(new MiddleMapElementNotKeyComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0);
} else {
mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
// Impossible to get here.
throw new AssertionError();
}
}
}
use of org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData in project hibernate-orm by hibernate.
the class CollectionMetadataGenerator method addWithMiddleTable.
@SuppressWarnings({ "unchecked" })
private void addWithMiddleTable() {
LOG.debugf("Adding audit mapping for property %s.%s: collection with a join table", referencingEntityName, propertyName);
// Generating the name of the middle table
String auditMiddleTableName;
String auditMiddleEntityName;
if (!StringTools.isEmpty(propertyAuditingData.getJoinTable().name())) {
auditMiddleTableName = propertyAuditingData.getJoinTable().name();
auditMiddleEntityName = propertyAuditingData.getJoinTable().name();
} else {
final String middleTableName = getMiddleTableName(propertyValue, referencingEntityName);
auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName(null, middleTableName);
auditMiddleEntityName = mainGenerator.getVerEntCfg().getAuditEntityName(middleTableName);
}
LOG.debugf("Using join table name: %s", 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.
Element middleEntityXml;
if (!propertyValue.isInverse()) {
// Generating a unique middle entity name
auditMiddleEntityName = mainGenerator.getAuditEntityNameRegister().createUnique(auditMiddleEntityName);
// Registering the generated name
mainGenerator.getAuditEntityNameRegister().register(auditMiddleEntityName);
middleEntityXml = createMiddleEntityXml(auditMiddleTableName, auditMiddleEntityName, propertyValue.getWhere());
} 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).
final IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// 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.getCollectionTable(), mainGenerator.getMetadata().getEntityBinding(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.
final 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.
final QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder(mainGenerator.getGlobalCfg(), mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData, auditMiddleEntityName, isRevisionTypeInId());
// 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.getColumnNameIterator(propertyValue.getKey().getColumnIterator()), referencingIdMapping);
}
// ******
// Generating the element mapping.
// ******
final MiddleComponentData elementComponentData = addValueToMiddleTable(propertyValue.getElement(), middleEntityXml, queryGeneratorBuilder, referencedPrefix, propertyAuditingData.getJoinTable().inverseJoinColumns(), !isLobMapElementType());
// ******
// Generating the index mapping, if an index exists.
// ******
final MiddleComponentData indexComponentData = addIndex(middleEntityXml, queryGeneratorBuilder);
// ******
// Generating the property mapper.
// ******
// Building the query generator.
final RelationQueryGenerator queryGenerator = queryGeneratorBuilder.build(elementComponentData, indexComponentData);
// Creating common data
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(mainGenerator.getVerEntCfg(), 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);
}
use of org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData in project hibernate-orm by hibernate.
the class CollectionMetadataGenerator method addOneToManyAttached.
@SuppressWarnings({ "unchecked" })
private void addOneToManyAttached(boolean fakeOneToManyBidirectional) {
LOG.debugf("Adding audit mapping for property %s.%s: one-to-many collection, using a join column on the referenced entity", referencingEntityName, propertyName);
// check whether the property has an @IndexColumn or @OrderColumn because its part of an
// IndexedCollection mapping type.
final boolean indexed = (propertyValue instanceof IndexedCollection) && ((IndexedCollection) propertyValue).getIndex() != null;
final String mappedBy = getMappedBy(propertyValue);
final IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData(referencingEntityName, referencedEntityName, propertyAuditingData, false);
final IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData();
// Generating the id mappers data for the referencing side of the relation.
final MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping, mappedBy + "_", referencingEntityName);
// And for the referenced side. The prefixed mapper won't be used (as this collection isn't persisted
// in a join table, so the prefix value is arbitrary).
final MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping, null, referencedEntityName);
// Generating the element mapping.
final MiddleComponentData elementComponentData = new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData), 0);
// Generating the index mapping, if an index exists. It can only exists in case a javax.persistence.MapKey
// annotation is present on the entity. So the middleEntityXml will be not be used. The queryGeneratorBuilder
// will only be checked for nullnes.
MiddleComponentData indexComponentData = addIndex(null, null);
// Generating the query generator - it should read directly from the related entity.
final RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator(mainGenerator.getGlobalCfg(), mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData, referencedEntityName, referencedIdData, isEmbeddableElementType(), mappedBy, isMappedByKey(propertyValue, mappedBy));
// Creating common mapper data.
final CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData(mainGenerator.getVerEntCfg(), referencedEntityName, propertyAuditingData.getPropertyData(), referencingIdData, queryGenerator);
PropertyMapper fakeBidirectionalRelationMapper;
PropertyMapper fakeBidirectionalRelationIndexMapper;
if (fakeOneToManyBidirectional || indexed) {
// In case of a fake many-to-one bidirectional relation, we have to generate a mapper which maps
// the mapped-by property name to the id of the related entity (which is the owner of the collection).
final String auditMappedBy;
if (fakeOneToManyBidirectional) {
auditMappedBy = propertyAuditingData.getAuditMappedBy();
} else {
auditMappedBy = propertyValue.getMappedByProperty();
}
// Creating a prefixed relation mapper.
final IdMapper relMapper = referencingIdMapping.getIdMapper().prefixMappedProperties(MappingTools.createToOneRelationPrefix(auditMappedBy));
fakeBidirectionalRelationMapper = new ToOneIdMapper(relMapper, // when constructing the PropertyData.
new PropertyData(auditMappedBy, null, null, null), referencingEntityName, false);
final String positionMappedBy;
if (fakeOneToManyBidirectional) {
positionMappedBy = propertyAuditingData.getPositionMappedBy();
} else if (indexed) {
final Value indexValue = ((IndexedCollection) propertyValue).getIndex();
positionMappedBy = indexValue.getColumnIterator().next().getText();
} else {
positionMappedBy = null;
}
// Checking if there's an index defined. If so, adding a mapper for it.
if (positionMappedBy != null) {
fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(new PropertyData(positionMappedBy, null, null, null));
// Also, overwriting the index component data to properly read the index.
indexComponentData = new MiddleComponentData(new MiddleStraightComponentMapper(positionMappedBy), 0);
} else {
fakeBidirectionalRelationIndexMapper = null;
}
} else {
fakeBidirectionalRelationMapper = null;
fakeBidirectionalRelationIndexMapper = null;
}
// Checking the type of the collection and adding an appropriate mapper.
addMapper(commonCollectionMapperData, elementComponentData, indexComponentData);
// Storing information about this relation.
referencingEntityConfiguration.addToManyNotOwningRelation(propertyName, mappedBy, referencedEntityName, referencingIdData.getPrefixedMapper(), fakeBidirectionalRelationMapper, fakeBidirectionalRelationIndexMapper, indexed);
}
use of org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData in project hibernate-orm by hibernate.
the class AuditAssociationQueryImpl method addCriterionsToQuery.
protected void addCriterionsToQuery(AuditReaderImplementor versionsReader) {
if (enversService.getEntitiesConfigurations().isVersioned(entityName)) {
String auditEntityName = enversService.getAuditEntitiesConfiguration().getAuditEntityName(entityName);
Parameters joinConditionParameters = queryBuilder.addJoin(joinType, auditEntityName, alias, false);
// owner.reference_id = target.originalId.id
AuditEntitiesConfiguration verEntCfg = enversService.getAuditEntitiesConfiguration();
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
IdMapper idMapperTarget = enversService.getEntitiesConfigurations().get(entityName).getIdMapper();
final String prefix = alias.concat(".").concat(originalIdPropertyName);
ownerAssociationIdMapper.addIdsEqualToQuery(joinConditionParameters, ownerAlias, idMapperTarget, prefix);
// filter revision of target entity
Parameters parametersToUse = parameters;
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
if (joinType == JoinType.LEFT) {
parametersToUse = parameters.addSubParameters(Parameters.OR);
parametersToUse.addNullRestriction(revisionPropertyPath, true);
parametersToUse = parametersToUse.addSubParameters(Parameters.AND);
}
MiddleIdData referencedIdData = new MiddleIdData(verEntCfg, enversService.getEntitiesConfigurations().get(entityName).getIdMappingData(), null, entityName, enversService.getEntitiesConfigurations().isVersioned(entityName));
enversService.getAuditStrategy().addEntityAtRevisionRestriction(enversService.getGlobalConfiguration(), queryBuilder, parametersToUse, revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true, referencedIdData, revisionPropertyPath, originalIdPropertyName, alias, queryBuilder.generateAlias(), true);
} else {
Parameters joinConditionParameters = queryBuilder.addJoin(joinType, entityName, alias, false);
// owner.reference_id = target.id
final IdMapper idMapperTarget = enversService.getEntitiesConfigurations().getNotVersionEntityConfiguration(entityName).getIdMapper();
ownerAssociationIdMapper.addIdsEqualToQuery(joinConditionParameters, ownerAlias, idMapperTarget, alias);
}
for (AuditCriterion criterion : criterions) {
criterion.addToQuery(enversService, versionsReader, aliasToEntityNameMap, alias, queryBuilder, parameters);
}
for (final AuditAssociationQueryImpl<?> sub : associationQueries) {
sub.addCriterionsToQuery(versionsReader);
}
}
use of org.hibernate.envers.internal.entities.mapper.relation.MiddleIdData in project hibernate-orm by hibernate.
the class EntitiesAtRevisionQuery method list.
public List list() {
/*
* The query that we need to create:
* SELECT new list(e) FROM versionsReferencedEntity e
* WHERE
* (all specified conditions, transformed, on the "e" entity) AND
* (selecting e entities at revision :revision)
* --> for DefaultAuditStrategy:
* e.revision = (SELECT max(e2.revision) FROM versionsReferencedEntity e2
* WHERE e2.revision <= :revision AND e2.id = e.id)
*
* --> for ValidityAuditStrategy:
* e.revision <= :revision and (e.endRevision > :revision or e.endRevision is null)
*
* AND
* (only non-deleted entities)
* e.revision_type != DEL
*/
AuditEntitiesConfiguration verEntCfg = enversService.getAuditEntitiesConfiguration();
String revisionPropertyPath = verEntCfg.getRevisionNumberPath();
String originalIdPropertyName = verEntCfg.getOriginalIdPropName();
MiddleIdData referencedIdData = new MiddleIdData(verEntCfg, enversService.getEntitiesConfigurations().get(entityName).getIdMappingData(), null, entityName, enversService.getEntitiesConfigurations().isVersioned(entityName));
// (selecting e entities at revision :revision)
// --> based on auditStrategy (see above)
enversService.getAuditStrategy().addEntityAtRevisionRestriction(enversService.getGlobalConfiguration(), qb, qb.getRootParameters(), revisionPropertyPath, verEntCfg.getRevisionEndFieldName(), true, referencedIdData, revisionPropertyPath, originalIdPropertyName, REFERENCED_ENTITY_ALIAS, REFERENCED_ENTITY_ALIAS_DEF_AUD_STR, true);
if (!includeDeletions) {
// e.revision_type != DEL
qb.getRootParameters().addWhereWithParam(verEntCfg.getRevisionTypePropName(), "<>", RevisionType.DEL);
}
// all specified conditions
for (AuditCriterion criterion : criterions) {
criterion.addToQuery(enversService, versionsReader, aliasToEntityNameMap, QueryConstants.REFERENCED_ENTITY_ALIAS, qb, qb.getRootParameters());
}
for (final AuditAssociationQueryImpl<?> associationQuery : associationQueries) {
associationQuery.addCriterionsToQuery(versionsReader);
}
Query query = buildQuery();
// add named parameter (used for ValidityAuditStrategy and association queries)
Collection<String> params = query.getParameterMetadata().getNamedParameterNames();
if (params.contains(REVISION_PARAMETER)) {
query.setParameter(REVISION_PARAMETER, revision);
}
List queryResult = query.list();
return applyProjections(queryResult, revision);
}
Aggregations