/**
   * Creates foreign keys for subclass tables that are mapped using table per subclass. Further
   * information is available in the <a href="http://jira.grails.org/browse/GRAILS-7729">JIRA
   * ticket</a>
   */
  private void createSubclassForeignKeys() {
    if (subclassForeignKeysCreated) {
      return;
    }

    for (PersistentClass persistentClass : classes.values()) {
      if (persistentClass instanceof RootClass) {
        RootClass rootClass = (RootClass) persistentClass;

        if (rootClass.hasSubclasses()) {
          Iterator subclasses = rootClass.getSubclassIterator();

          while (subclasses.hasNext()) {

            Object subclass = subclasses.next();

            // This test ensures that foreign keys will only be created for subclasses that are
            // mapped using "table per subclass"
            if (subclass instanceof JoinedSubclass) {
              JoinedSubclass joinedSubclass = (JoinedSubclass) subclass;
              joinedSubclass.createForeignKey();
            }
          }
        }
      }
    }

    subclassForeignKeysCreated = true;
  }
示例#2
0
  /**
   * bind many-to-ones
   *
   * @param table
   * @param rc
   * @param primaryKey
   */
  private void bindOutgoingForeignKeys(Table table, RootClass rc, Set processedColumns) {

    // Iterate the outgoing foreign keys and create many-to-one's
    for (Iterator iterator = table.getForeignKeyIterator(); iterator.hasNext(); ) {
      ForeignKey foreignKey = (ForeignKey) iterator.next();

      boolean mutable = true;
      if (contains(foreignKey.getColumnIterator(), processedColumns)) {
        if (!cfg.preferBasicCompositeIds()) continue; // it's in the pk, so skip this one
        mutable = false;
      }

      if (revengStrategy.excludeForeignKeyAsManytoOne(
          foreignKey.getName(),
          TableIdentifier.create(foreignKey.getTable()),
          foreignKey.getColumns(),
          TableIdentifier.create(foreignKey.getReferencedTable()),
          foreignKey.getReferencedColumns())) {
        // TODO: if many-to-one is excluded should the column be marked as processed so it won't
        // show up at all ?
        log.debug("Rev.eng excluded *-to-one for foreignkey " + foreignKey.getName());
      } else if (revengStrategy.isOneToOne(foreignKey)) {
        Property property =
            bindOneToOne(
                rc, foreignKey.getReferencedTable(), foreignKey, processedColumns, true, false);
        rc.addProperty(property);
      } else {
        boolean isUnique = isUniqueReference(foreignKey);
        String propertyName =
            revengStrategy.foreignKeyToEntityName(
                foreignKey.getName(),
                TableIdentifier.create(foreignKey.getTable()),
                foreignKey.getColumns(),
                TableIdentifier.create(foreignKey.getReferencedTable()),
                foreignKey.getReferencedColumns(),
                isUnique);

        Property property =
            bindManyToOne(
                makeUnique(rc, propertyName), mutable, table, foreignKey, processedColumns);

        rc.addProperty(property);
      }
    }
  }
示例#3
0
  private void bindVersionProperty(
      Table table,
      TableIdentifier identifier,
      Column column,
      RootClass rc,
      Set processed,
      Mapping mapping) {

    processed.add(column);
    String propertyName = revengStrategy.columnToPropertyName(identifier, column.getName());
    Property property =
        bindBasicProperty(makeUnique(rc, propertyName), table, column, processed, mapping);
    rc.addProperty(property);
    rc.setVersion(property);
    rc.setOptimisticLockMode(Versioning.OPTIMISTIC_LOCK_VERSION);
    log.debug(
        "Column "
            + column.getName()
            + " will be used for <version>/<timestamp> columns in "
            + identifier);
  }
示例#4
0
 private Property getConstrainedOneToOne(RootClass rc) {
   Iterator propertyClosureIterator = rc.getPropertyClosureIterator();
   while (propertyClosureIterator.hasNext()) {
     Property property = (Property) propertyClosureIterator.next();
     if (property.getValue() instanceof OneToOne) {
       OneToOne oto = (OneToOne) property.getValue();
       if (oto.isConstrained()) {
         return property;
       }
     }
   }
   return null;
 }
示例#5
0
  private void updatePrimaryKey(RootClass rc, PrimaryKeyInfo pki) {
    SimpleValue idValue = (SimpleValue) rc.getIdentifierProperty().getValue();

    Properties defaultStrategyProperties = new Properties();
    Property constrainedOneToOne = getConstrainedOneToOne(rc);
    if (constrainedOneToOne != null) {
      if (pki.suggestedStrategy == null) {
        idValue.setIdentifierGeneratorStrategy("foreign");
      }

      if (pki.suggestedProperties == null) {
        defaultStrategyProperties.setProperty("property", constrainedOneToOne.getName());
        idValue.setIdentifierGeneratorProperties(defaultStrategyProperties);
      }
    }
  }
示例#6
0
  /**
   * @param table
   * @param rc
   * @param primaryKey
   */
  private void bindColumnsToProperties(
      Table table, RootClass rc, Set processedColumns, Mapping mapping) {

    for (Iterator iterator = table.getColumnIterator(); iterator.hasNext(); ) {
      Column column = (Column) iterator.next();
      if (!processedColumns.contains(column)) {
        checkColumn(column);

        String propertyName =
            revengStrategy.columnToPropertyName(TableIdentifier.create(table), column.getName());

        Property property =
            bindBasicProperty(
                makeUnique(rc, propertyName), table, column, processedColumns, mapping);

        rc.addProperty(property);
      }
    }
  }
示例#7
0
  /**
   * Basically create an [classname]Id.class and add properties for it.
   *
   * @param rc
   * @param compositeKeyColumns
   * @param processed
   * @return
   */
  private SimpleValue handleCompositeKey(
      RootClass rc, Set processedColumns, List keyColumns, Mapping mapping) {
    Component pkc = new Component(rc);
    pkc.setMetaAttributes(Collections.EMPTY_MAP);
    pkc.setEmbedded(false);

    String compositeIdName =
        revengStrategy.tableToCompositeIdName(TableIdentifier.create(rc.getTable()));
    if (compositeIdName == null) {
      compositeIdName = revengStrategy.classNameToCompositeIdName(rc.getClassName());
    }
    pkc.setComponentClassName(compositeIdName);
    Table table = rc.getTable();
    List list = null;
    if (cfg.preferBasicCompositeIds()) {
      list = new ArrayList(keyColumns);
    } else {
      list = findForeignKeys(table.getForeignKeyIterator(), keyColumns);
    }
    for (Iterator iter = list.iterator(); iter.hasNext(); ) {
      Object element = iter.next();
      Property property;
      if (element instanceof Column) {
        Column column = (Column) element;
        if (processedColumns.contains(column)) {
          throw new JDBCBinderException(
              "Binding column twice for primary key should not happen: " + column);
        } else {
          checkColumn(column);

          String propertyName =
              revengStrategy.columnToPropertyName(TableIdentifier.create(table), column.getName());
          property =
              bindBasicProperty(
                  makeUnique(pkc, propertyName), table, column, processedColumns, mapping);

          processedColumns.add(column);
        }
      } else if (element instanceof ForeignKeyForColumns) {
        ForeignKeyForColumns fkfc = (ForeignKeyForColumns) element;
        ForeignKey foreignKey = fkfc.key;
        String propertyName =
            revengStrategy.foreignKeyToEntityName(
                foreignKey.getName(),
                TableIdentifier.create(foreignKey.getTable()),
                foreignKey.getColumns(),
                TableIdentifier.create(foreignKey.getReferencedTable()),
                foreignKey.getReferencedColumns(),
                true);
        property =
            bindManyToOne(makeUnique(pkc, propertyName), true, table, foreignKey, processedColumns);
        processedColumns.addAll(fkfc.columns);
      } else {
        throw new JDBCBinderException("unknown thing");
      }

      markAsUseInEquals(property);
      pkc.addProperty(property);
    }

    return pkc;
  }
示例#8
0
  private PrimaryKeyInfo bindPrimaryKeyToProperties(
      Table table, RootClass rc, Set processed, Mapping mapping, DatabaseCollector collector) {
    SimpleValue id = null;
    String idPropertyname = null;

    PrimaryKeyInfo pki = new PrimaryKeyInfo();

    List keyColumns = null;
    if (table.getPrimaryKey() != null) {
      keyColumns = table.getPrimaryKey().getColumns();
    } else {
      log.debug("No primary key found for " + table + ", using all properties as the identifier.");
      keyColumns = new ArrayList();
      Iterator iter = table.getColumnIterator();
      while (iter.hasNext()) {
        Column col = (Column) iter.next();
        keyColumns.add(col);
      }
    }

    final TableIdentifier tableIdentifier = TableIdentifier.create(table);

    String tableIdentifierStrategyName = "assigned";

    boolean naturalId;

    if (keyColumns.size() > 1) {
      log.debug(
          "id strategy for " + rc.getEntityName() + " since it has a multiple column primary key");
      naturalId = true;

      id = handleCompositeKey(rc, processed, keyColumns, mapping);
      idPropertyname = revengStrategy.tableToIdentifierPropertyName(tableIdentifier);
      if (idPropertyname == null) {
        idPropertyname = "id";
      }
    } else {
      pki.suggestedStrategy = revengStrategy.getTableIdentifierStrategyName(tableIdentifier);
      String suggestedStrategy = pki.suggestedStrategy;
      if (suggestedStrategy == null) {
        suggestedStrategy =
            collector.getSuggestedIdentifierStrategy(
                tableIdentifier.getCatalog(),
                tableIdentifier.getSchema(),
                tableIdentifier.getName());
        if (suggestedStrategy == null) {
          suggestedStrategy = "assigned";
        }
        tableIdentifierStrategyName = suggestedStrategy;
      } else {
        tableIdentifierStrategyName = suggestedStrategy;
      }

      naturalId = "assigned".equals(tableIdentifierStrategyName);
      Column pkc = (Column) keyColumns.get(0);
      checkColumn(pkc);

      id = bindColumnToSimpleValue(table, pkc, mapping, !naturalId);

      idPropertyname = revengStrategy.tableToIdentifierPropertyName(tableIdentifier);
      if (idPropertyname == null) {
        idPropertyname = revengStrategy.columnToPropertyName(tableIdentifier, pkc.getName());
      }

      processed.add(pkc);
    }
    id.setIdentifierGeneratorStrategy(tableIdentifierStrategyName);
    pki.suggestedProperties = revengStrategy.getTableIdentifierProperties(tableIdentifier);
    id.setIdentifierGeneratorProperties(pki.suggestedProperties);
    if (naturalId) {
      id.setNullValue("undefined");
    }

    Property property =
        makeProperty(
            tableIdentifier, makeUnique(rc, idPropertyname), id, true, true, false, null, null);
    rc.setIdentifierProperty(property);
    rc.setIdentifier(id);

    return pki;
  }
示例#9
0
  /**
   * @param manyToOneCandidates
   * @param mappings2
   */
  private void createPersistentClasses(DatabaseCollector collector, Mapping mapping) {
    Map manyToOneCandidates = collector.getOneToManyCandidates();

    for (Iterator iter = mappings.iterateTables(); iter.hasNext(); ) {
      Table table = (Table) iter.next();
      if (table.getColumnSpan() == 0) {
        log.warn("Cannot create persistent class for " + table + " as no columns were found.");
        continue;
      }
      // TODO: this naively just create an entity per table
      // should have an opt-out option to mark some as helper tables, subclasses etc.
      /*if(table.getPrimaryKey()==null || table.getPrimaryKey().getColumnSpan()==0) {
      log.warn("Cannot create persistent class for " + table + " as no primary key was found.");
               continue;
               // TODO: just create one big embedded composite id instead.
           }*/

      if (revengStrategy.isManyToManyTable(table)) {
        log.debug("Ignoring " + table + " as class since rev.eng. says it is a many-to-many");
        continue;
      }

      RootClass rc = new RootClass();
      TableIdentifier tableIdentifier = TableIdentifier.create(table);
      String className = revengStrategy.tableToClassName(tableIdentifier);
      log.debug("Building entity " + className + " based on " + tableIdentifier);
      rc.setEntityName(className);
      rc.setClassName(className);
      rc.setProxyInterfaceName(rc.getEntityName()); // TODO: configurable ?
      rc.setLazy(true);

      rc.setMetaAttributes(safeMeta(revengStrategy.tableToMetaAttributes(tableIdentifier)));

      rc.setDiscriminatorValue(rc.getEntityName());
      rc.setTable(table);
      try {
        mappings.addClass(rc);
      } catch (DuplicateMappingException dme) {
        // TODO: detect this and generate a "permutation" of it ?
        PersistentClass class1 = mappings.getClass(dme.getName());
        Table table2 = class1.getTable();
        throw new JDBCBinderException(
            "Duplicate class name '"
                + rc.getEntityName()
                + "' generated for '"
                + table
                + "'. Same name where generated for '"
                + table2
                + "'");
      }
      mappings.addImport(rc.getEntityName(), rc.getEntityName());

      Set processed = new HashSet();

      PrimaryKeyInfo pki = bindPrimaryKeyToProperties(table, rc, processed, mapping, collector);
      bindColumnsToVersioning(table, rc, processed, mapping);
      bindOutgoingForeignKeys(table, rc, processed);
      bindColumnsToProperties(table, rc, processed, mapping);
      List incomingForeignKeys = (List) manyToOneCandidates.get(rc.getEntityName());
      bindIncomingForeignKeys(rc, processed, incomingForeignKeys, mapping);
      updatePrimaryKey(rc, pki);
    }
  }