@SuppressWarnings({"unchecked"})
  private boolean addIdProperties(
      Element parent,
      Iterator<Property> properties,
      SimpleMapperBuilder mapper,
      boolean key,
      boolean audited) {
    while (properties.hasNext()) {
      Property property = properties.next();
      Type propertyType = property.getType();
      if (!"_identifierMapper".equals(property.getName())) {
        // Last but one parameter: ids are always insertable
        boolean added =
            mainGenerator
                .getBasicMetadataGenerator()
                .addBasic(
                    parent,
                    getIdPersistentPropertyAuditingData(property),
                    property.getValue(),
                    mapper,
                    true,
                    key);

        if (!added) {
          // If the entity is audited, and a non-supported id component is used, throwing an
          // exception.
          // If the entity is not audited, then we simply don't support this entity, even in
          // target relation mode not audited.
          if (audited) {
            throw new MappingException("Type not supported: " + propertyType.getClass().getName());
          } else {
            return false;
          }
        }
      }
    }

    return true;
  }
  /**
   * @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) {
    Type type = value.getType();
    if (type instanceof 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.getColumnNameIterator(joinColumns)
                : MetadataTools.getColumnNameIterator(value.getColumnIterator()),
            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.getCurrentIndex());
    } else {
      // Last but one parameter: collection components are always insertable
      boolean mapped =
          mainGenerator
              .getBasicMetadataGenerator()
              .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.getVerEntCfg(), prefix), 0);
      } else {
        mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName);
        // Impossible to get here.
        throw new AssertionError();
      }
    }
  }
  @SuppressWarnings({"unchecked"})
  IdMappingData addId(PersistentClass pc, boolean audited) {
    // Xml mapping which will be used for relations
    Element rel_id_mapping = new DefaultElement("properties");
    // Xml mapping which will be used for the primary key of the versions table
    Element orig_id_mapping = new DefaultElement("composite-id");

    Property id_prop = pc.getIdentifierProperty();
    Component id_mapper = pc.getIdentifierMapper();

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

    SimpleIdMapperBuilder mapper;
    if (id_mapper != null) {
      // Multiple id

      mapper = new MultipleIdMapper(((Component) pc.getIdentifier()).getComponentClassName());
      if (!addIdProperties(
          rel_id_mapping,
          (Iterator<Property>) id_mapper.getPropertyIterator(),
          mapper,
          false,
          audited)) {
        return null;
      }

      // null mapper - the mapping where already added the first time, now we only want to generate
      // the xml
      if (!addIdProperties(
          orig_id_mapping,
          (Iterator<Property>) id_mapper.getPropertyIterator(),
          null,
          true,
          audited)) {
        return null;
      }
    } else if (id_prop.isComposite()) {
      // Embedded id

      Component id_component = (Component) id_prop.getValue();

      mapper =
          new EmbeddedIdMapper(getIdPropertyData(id_prop), id_component.getComponentClassName());
      if (!addIdProperties(
          rel_id_mapping,
          (Iterator<Property>) id_component.getPropertyIterator(),
          mapper,
          false,
          audited)) {
        return null;
      }

      // null mapper - the mapping where already added the first time, now we only want to generate
      // the xml
      if (!addIdProperties(
          orig_id_mapping,
          (Iterator<Property>) id_component.getPropertyIterator(),
          null,
          true,
          audited)) {
        return null;
      }
    } else {
      // Single id

      mapper = new SingleIdMapper();

      // Last but one parameter: ids are always insertable
      mainGenerator
          .getBasicMetadataGenerator()
          .addBasic(
              rel_id_mapping,
              getIdPersistentPropertyAuditingData(id_prop),
              id_prop.getValue(),
              mapper,
              true,
              false);

      // null mapper - the mapping where already added the first time, now we only want to generate
      // the xml
      mainGenerator
          .getBasicMetadataGenerator()
          .addBasic(
              orig_id_mapping,
              getIdPersistentPropertyAuditingData(id_prop),
              id_prop.getValue(),
              null,
              true,
              true);
    }

    orig_id_mapping.addAttribute("name", mainGenerator.getVerEntCfg().getOriginalIdPropName());

    // Adding a relation to the revision entity (effectively: the "revision number" property)
    mainGenerator.addRevisionInfoRelation(orig_id_mapping);

    return new IdMappingData(mapper, orig_id_mapping, rel_id_mapping);
  }