/// <summary> /// Ctor /// </summary> /// <param name="metaDataStore"></param> /// <param name="mainGenerator">Main generator, giving access to configuration and the basic mapper.</param> /// <param name="propertyValue">Value of the collection, as mapped by Hibernate.</param> /// <param name="currentMapper">Mapper, to which the appropriate {@link org.hibernate.envers.entities.mapper.PropertyMapper} will be added.</param> /// <param name="referencingEntityName">Name of the entity that owns this collection.</param> /// <param name="xmlMappingData">In case this collection requires a middle table, additional mapping documents will be created using this object.</param> /// <param name="propertyAuditingData"> /// Property auditing (meta-)data. Among other things, holds the name of the /// property that references the collection in the referencing entity, the user data for middle (join) /// table and the value of the <code>@MapKey</code> annotation, if there was one. /// </param> public CollectionMetadataGenerator(IMetaDataStore metaDataStore, AuditMetadataGenerator mainGenerator, Mapping.Collection propertyValue, ICompositeMapperBuilder currentMapper, string referencingEntityName, EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData) { _metaDataStore = metaDataStore; _mainGenerator = mainGenerator; _propertyValue = propertyValue; _currentMapper = currentMapper; _referencingEntityName = referencingEntityName; _xmlMappingData = xmlMappingData; _propertyAuditingData = propertyAuditingData; _propertyName = propertyAuditingData.Name; _referencingEntityConfiguration = mainGenerator.EntitiesConfigurations[referencingEntityName]; if (_referencingEntityConfiguration == null) { throw new MappingException("Unable to read auditing configuration for " + referencingEntityName + "!"); } _referencedEntityName = MappingTools.ReferencedEntityName(propertyValue.Element); }
/// <summary> /// After all meta-data is read, updates calculated fields. This includes: /// <ul> /// <li>setting {@code forceInsertable} to {@code true} for properties specified by {@code @AuditMappedBy}</li> /// </ul> /// </summary> public void UpdateCalculatedFields() { foreach (var classAuditingDataEntry in persistentClassToAuditingData) { var pc = classAuditingDataEntry.Key; var classAuditingData = classAuditingDataEntry.Value; foreach (var propertyName in classAuditingData.PropertyNames) { var propertyAuditingData = classAuditingData.GetPropertyAuditingData(propertyName); // If a property had the @AuditMappedBy annotation, setting the referenced fields to be always insertable. if (propertyAuditingData.ForceInsertable) { var referencedEntityName = MappingTools.ReferencedEntityName(pc.GetProperty(propertyName).Value); var referencedClassAuditingData = entityNameToAuditingData[referencedEntityName]; forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.MappedBy, pc.EntityName, referencedEntityName); forcePropertyInsertable(referencedClassAuditingData, propertyAuditingData.PositionMappedBy, pc.EntityName, referencedEntityName); } } } }
private void addBidirectionalInfo(IDictionary <System.Type, IEntityMeta> metas) { foreach (var type in metas.Keys) { var persistentClass = _nhibernateConfiguration.GetClassMapping(type); if (persistentClass == null) { continue; } foreach (var property in persistentClass.PropertyIterator) { //is it a collection? var collectionValue = property.Value as Mapping.Collection; if (collectionValue == null) { continue; } //find referenced entity name var referencedEntity = MappingTools.ReferencedEntityName(property.Value); if (referencedEntity == null) { continue; } var refPersistentClass = _nhibernateConfiguration.GetClassMapping(referencedEntity); foreach (var refProperty in refPersistentClass.PropertyClosureIterator) { var attr = createAuditMappedByAttributeIfReferenceImmutable(collectionValue, refProperty); if (attr == null) { continue; } mightAddIndexToAttribute(attr, collectionValue, refPersistentClass.PropertyClosureIterator); var entityMeta = (EntityMeta)metas[type]; var declaredPersistentProperty = PropertyAndMemberInfo.PersistentInfo(type, new[] { property }).FirstOrDefault(); if (declaredPersistentProperty == null) { //pawel owerko log.WarnFormat(string.Format("Cannot create '{0}' object for property '{1}'. Property not found in type '{2}'.", typeof(DeclaredPersistentProperty).Name, property.Name, type.FullName)); continue; //todo: Can we handle declaredPersistentProperty==null in that way ? } var methodInfo = declaredPersistentProperty.Member; addToEntityMeta(attr, entityMeta, methodInfo); } } } }
private void addBidirectionalInfo(IDictionary <System.Type, IEntityMeta> metas) { foreach (var type in metas.Keys) { var persistentClass = _nhibernateConfiguration.GetClassMapping(type); if (persistentClass == null) { continue; } foreach (var property in persistentClass.PropertyIterator) { //is it a collection? var collectionValue = property.Value as Mapping.Collection; if (collectionValue == null) { continue; } //find referenced entity name var referencedEntity = MappingTools.ReferencedEntityName(property.Value); if (referencedEntity == null) { continue; } var refPersistentClass = _nhibernateConfiguration.GetClassMapping(referencedEntity); foreach (var refProperty in refPersistentClass.PropertyClosureIterator) { if (MetadataTools.IsNoneAccess(refProperty.PropertyAccessorName)) { continue; } var attr = createAuditMappedByAttributeIfReferenceImmutable(collectionValue, refProperty); if (attr == null) { continue; } mightAddIndexToAttribute(attr, collectionValue, refPersistentClass.PropertyClosureIterator); var entityMeta = (EntityMeta)metas[type]; var methodInfo = PropertyAndMemberInfo.PersistentInfo(type, new[] { property }).First().Member; addToEntityMeta(attr, entityMeta, methodInfo); } } } }
private string getMappedBy(Mapping.Collection collectionValue) { var referencedClass = _mainGenerator.Cfg.GetClassMapping(MappingTools.ReferencedEntityName(collectionValue.Element)); var mappedBy = searchMappedBy(referencedClass, collectionValue); if (mappedBy == null) { log.Debug("Going to search the mapped by attribute for " + _propertyName + " in superclasses of entity: " + referencedClass.ClassName); var tempClass = referencedClass; while (mappedBy == null && tempClass.Superclass != null) { log.Debug("Searching in superclass: " + tempClass.Superclass.ClassName); mappedBy = searchMappedBy(tempClass.Superclass, collectionValue); tempClass = tempClass.Superclass; } } if (mappedBy == null) { throw new MappingException("Cannot find the inverse side for " + _propertyName + " in " + _referencingEntityName + "!"); } return(mappedBy); }
/// <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(); }