private Element createMiddleEntityXml(
      String auditMiddleTableName, String auditMiddleEntityName, String where) {
    String schema =
        mainGenerator.getSchema(
            propertyAuditingData.getJoinTable().schema(), propertyValue.getCollectionTable());
    String catalog =
        mainGenerator.getCatalog(
            propertyAuditingData.getJoinTable().catalog(), propertyValue.getCollectionTable());

    Element middleEntityXml =
        MetadataTools.createEntity(
            xmlMappingData.newAdditionalMapping(),
            new AuditTableData(auditMiddleEntityName, auditMiddleTableName, schema, catalog),
            null);
    Element middleEntityXmlId = middleEntityXml.addElement("composite-id");

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

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

    // 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;
  }
 private String getMiddleTableName(Collection value, String entityName) {
   // We check how Hibernate maps the collection.
   if (value.getElement() instanceof OneToMany && !value.isInverse()) {
     // This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate
     // doesn't use a
     // middle table for mapping this relation.
     return StringTools.getLastComponent(entityName)
         + "_"
         + StringTools.getLastComponent(MappingTools.getReferencedEntityName(value.getElement()));
   }
   // Hibernate uses a middle table for mapping this relation, so we get it's name directly.
   return value.getCollectionTable().getName();
 }
  @Test
  public void testWithJpaCompliantNamingStrategy() throws Exception {
    Metadata metadata =
        new MetadataSources(serviceRegistry)
            .addAnnotatedClass(A.class)
            .addAnnotatedClass(AddressEntry.class)
            .getMetadataBuilder()
            .applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE)
            .build();

    Collection collectionBinding = metadata.getCollectionBinding(A.class.getName() + ".address");
    assertEquals(
        "Expecting A#address collection table name (implicit) to be [A_address] per JPA spec (section 11.1.8)",
        "A_ADDRESS",
        collectionBinding.getCollectionTable().getQuotedName().toUpperCase(Locale.ROOT));
  }
  @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 {
      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).
    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.getCfg().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.getGlobalCfg(),
            mainGenerator.getVerEntCfg(),
            mainGenerator.getAuditStrategy(),
            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.getColumnNameIterator(propertyValue.getKey().getColumnIterator()),
          referencingIdMapping);
    }

    // ******
    // Generating the element mapping.
    // ******
    MiddleComponentData elementComponentData =
        addValueToMiddleTable(
            propertyValue.getElement(),
            middleEntityXml,
            queryGeneratorBuilder,
            referencedPrefix,
            propertyAuditingData.getJoinTable().inverseJoinColumns());

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

    // ******
    // Generating the property mapper.
    // ******
    // Building the query generator.
    RelationQueryGenerator queryGenerator =
        queryGeneratorBuilder.build(elementComponentData, indexComponentData);

    // Creating common data
    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);
  }
Example #5
0
  /**
   * @param rc
   * @param processed
   * @param table
   * @param object
   */
  private Property bindOneToMany(
      PersistentClass rc, ForeignKey foreignKey, Set processed, Mapping mapping) {

    Table collectionTable = foreignKey.getTable();

    //		Collection collection = new org.hibernate.mapping.Set(rc); // MASTER TODO: allow overriding
    // collection type
    Collection collection =
        new org.hibernate.mapping.List(rc); // MASTER TODO: allow overriding collection type

    collection.setCollectionTable(collectionTable); // CHILD+

    boolean manyToMany = revengStrategy.isManyToManyTable(collectionTable);
    if (manyToMany) {
      // log.debug("Rev.eng said here is a many-to-many");
      // TODO: handle "the other side should influence the name"
    }

    if (manyToMany) {

      ManyToOne element = new ManyToOne(collection.getCollectionTable());
      // TODO: find the other foreignkey and choose the other side.
      Iterator foreignKeyIterator = foreignKey.getTable().getForeignKeyIterator();
      List keys = new ArrayList();
      while (foreignKeyIterator.hasNext()) {
        Object next = foreignKeyIterator.next();
        if (next != foreignKey) {
          keys.add(next);
        }
      }

      if (keys.size() > 1) {
        throw new JDBCBinderException(
            "more than one other foreign key to choose from!"); // todo: handle better ?
      }

      ForeignKey fk = (ForeignKey) keys.get(0);

      String tableToClassName = bindCollection(rc, foreignKey, fk, collection);

      element.setReferencedEntityName(tableToClassName);
      element.addColumn(fk.getColumn(0));
      collection.setElement(element);

    } else {
      String tableToClassName = bindCollection(rc, foreignKey, null, collection);

      OneToMany oneToMany = new OneToMany(collection.getOwner());

      oneToMany.setReferencedEntityName(tableToClassName); // Child
      mappings.addSecondPass(new JDBCCollectionSecondPass(mappings, collection));

      collection.setElement(oneToMany);
    }
    // bind keyvalue
    KeyValue referencedKeyValue;
    String propRef = collection.getReferencedPropertyName();
    if (propRef == null) {
      referencedKeyValue = collection.getOwner().getIdentifier();
    } else {
      referencedKeyValue = (KeyValue) collection.getOwner().getProperty(propRef).getValue();
    }

    SimpleValue keyValue = new DependantValue(collectionTable, referencedKeyValue);
    // keyValue.setForeignKeyName("none"); // Avoid creating the foreignkey
    // key.setCascadeDeleteEnabled( "cascade".equals( subnode.attributeValue("on-delete") ) );
    Iterator columnIterator = foreignKey.getColumnIterator();
    while (columnIterator.hasNext()) {
      Column fkcolumn = (Column) columnIterator.next();
      if (fkcolumn.getSqlTypeCode()
          != null) { // TODO: user defined foreign ref columns does not have a type set.
        guessAndAlignType(
            collectionTable,
            fkcolumn,
            mapping,
            false); // needed to ensure foreign key columns has same type as the "property" column.
      }
      keyValue.addColumn(fkcolumn);
    }

    collection.setKey(keyValue);

    mappings.addCollection(collection);

    return makeCollectionProperty(
        StringHelper.unqualify(collection.getRole()),
        true,
        rc.getTable(),
        foreignKey,
        collection,
        true);
    // return makeProperty(TableIdentifier.create( rc.getTable() ), StringHelper.unqualify(
    // collection.getRole() ), collection, true, true, true, "none", null); // TODO: cascade isn't
    // all by default

  }