Search in sources :

Example 6 with ForeignKey

use of org.datanucleus.store.rdbms.key.ForeignKey in project datanucleus-rdbms by datanucleus.

the class ElementContainerTable method getForeignKeyToElement.

/**
 * Convenience method to generate a ForeignKey from this join table to an element table using the specified mapping.
 * @param elementTable The element table
 * @param autoMode Whether we are in auto mode (where we generate the keys regardless of what the metadata says)
 * @param m The mapping to the element table
 * @return The ForeignKey
 */
protected ForeignKey getForeignKeyToElement(DatastoreClass elementTable, boolean autoMode, JavaTypeMapping m) {
    ForeignKey fk = null;
    if (elementTable != null) {
        // Take <foreign-key> from either <field> or <element>
        ForeignKeyMetaData fkmd = mmd.getForeignKeyMetaData();
        if (fkmd == null && mmd.getElementMetaData() != null) {
            fkmd = mmd.getElementMetaData().getForeignKeyMetaData();
        }
        // TODO If in autoMode and there are multiple possible element tables then don't create a FK
        if (fkmd != null || autoMode) {
            fk = new ForeignKey(m, dba, elementTable, true);
            fk.setForMetaData(fkmd);
        }
    }
    return fk;
}
Also used : ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey)

Example 7 with ForeignKey

use of org.datanucleus.store.rdbms.key.ForeignKey in project datanucleus-rdbms by datanucleus.

the class SecondaryTable method getExpectedForeignKeys.

/**
 * Accessor for the expected foreign keys for this table.
 * @return The expected foreign keys.
 */
protected List<ForeignKey> getExpectedForeignKeys() {
    assertIsInitialized();
    // Auto mode allows us to decide which FKs are needed as well as using what is in the users MetaData.
    boolean autoMode = false;
    if (storeMgr.getStringProperty(RDBMSPropertyNames.PROPERTY_RDBMS_CONSTRAINT_CREATE_MODE).equals("DataNucleus")) {
        autoMode = true;
    }
    // Add FK back to the primary table unless requested not to
    List<ForeignKey> foreignKeys = new ArrayList<>();
    ForeignKeyMetaData fkmd = joinMetaData != null ? joinMetaData.getForeignKeyMetaData() : null;
    if (autoMode || (fkmd != null && fkmd.getDeleteAction() != ForeignKeyAction.NONE)) {
        ForeignKey fk = new ForeignKey(getIdMapping(), dba, primaryTable, fkmd != null && fkmd.isDeferred() ? true : false);
        if (fkmd != null && fkmd.getName() != null) {
            fk.setName(fkmd.getName());
        }
        foreignKeys.add(0, fk);
    }
    return foreignKeys;
}
Also used : ArrayList(java.util.ArrayList) ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey)

Example 8 with ForeignKey

use of org.datanucleus.store.rdbms.key.ForeignKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method getSQLAddFKStatements.

/**
 * Get SQL statements to add expected Foreign Keys that are not yet at the table.
 * If the returned Map is empty, the current FK setup is correct.
 * @param actualForeignKeysByName Actual Map of foreign keys
 * @param clr The ClassLoaderResolver
 * @return a Map with the SQL statements
 */
protected Map<String, String> getSQLAddFKStatements(Map actualForeignKeysByName, ClassLoaderResolver clr) {
    assertIsInitialized();
    Map<String, String> stmtsByFKName = new HashMap<>();
    List<ForeignKey> expectedForeignKeys = getExpectedForeignKeys(clr);
    Iterator<ForeignKey> i = expectedForeignKeys.iterator();
    int n = 1;
    IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
    while (i.hasNext()) {
        ForeignKey fk = i.next();
        if (!actualForeignKeysByName.containsValue(fk)) {
            // If no name assigned, make one up
            if (fk.getName() == null) {
                // Use the ForeignKeyIdentifier to generate the name
                DatastoreIdentifier fkName;
                do {
                    fkName = idFactory.newForeignKeyIdentifier(this, n++);
                } while (actualForeignKeysByName.containsKey(fkName));
                fk.setName(fkName.getName());
            }
            String stmtText = dba.getAddForeignKeyStatement(fk, idFactory);
            if (stmtText != null) {
                stmtsByFKName.put(fk.getName(), stmtText);
            }
        }
    }
    return stmtsByFKName;
}
Also used : HashMap(java.util.HashMap) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory)

Example 9 with ForeignKey

use of org.datanucleus.store.rdbms.key.ForeignKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method getExistingForeignKeys.

/**
 * Accessor for the foreign keys for this table.
 * @param conn The JDBC Connection
 * @return Map of foreign keys
 * @throws SQLException Thrown when an error occurs in the JDBC call.
 */
private Map<DatastoreIdentifier, ForeignKey> getExistingForeignKeys(Connection conn) throws SQLException {
    Map<DatastoreIdentifier, ForeignKey> foreignKeysByName = new HashMap<>();
    if (tableExistsInDatastore(conn)) {
        StoreSchemaHandler handler = storeMgr.getSchemaHandler();
        IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
        RDBMSTableFKInfo tableFkInfo = (RDBMSTableFKInfo) handler.getSchemaData(conn, RDBMSSchemaHandler.TYPE_FKS, new Object[] { this });
        Iterator fksIter = tableFkInfo.getChildren().iterator();
        while (fksIter.hasNext()) {
            ForeignKeyInfo fkInfo = (ForeignKeyInfo) fksIter.next();
            DatastoreIdentifier fkIdentifier;
            String fkName = (String) fkInfo.getProperty("fk_name");
            if (fkName == null) {
                fkIdentifier = idFactory.newForeignKeyIdentifier(this, foreignKeysByName.size());
            } else {
                fkIdentifier = idFactory.newIdentifier(IdentifierType.FOREIGN_KEY, fkName);
            }
            short deferrability = ((Short) fkInfo.getProperty("deferrability")).shortValue();
            boolean initiallyDeferred = deferrability == DatabaseMetaData.importedKeyInitiallyDeferred;
            ForeignKey fk = foreignKeysByName.get(fkIdentifier);
            if (fk == null) {
                fk = new ForeignKey(dba, initiallyDeferred);
                fk.setName(fkIdentifier.getName());
                foreignKeysByName.put(fkIdentifier, fk);
            }
            // Find the referenced table from the provided name
            String pkTableName = (String) fkInfo.getProperty("pk_table_name");
            DatastoreIdentifier refTableId = idFactory.newTableIdentifier(pkTableName);
            DatastoreClass refTable = storeMgr.getDatastoreClass(refTableId);
            if (refTable == null) {
                // Try with same catalog/schema as this table since some JDBC don't provide this info
                if (getSchemaName() != null) {
                    refTableId.setSchemaName(getSchemaName());
                }
                if (getCatalogName() != null) {
                    refTableId.setCatalogName(getCatalogName());
                }
                refTable = storeMgr.getDatastoreClass(refTableId);
            }
            if (refTable != null) {
                String fkColumnName = (String) fkInfo.getProperty("fk_column_name");
                String pkColumnName = (String) fkInfo.getProperty("pk_column_name");
                DatastoreIdentifier colName = idFactory.newIdentifier(IdentifierType.COLUMN, fkColumnName);
                DatastoreIdentifier refColName = idFactory.newIdentifier(IdentifierType.COLUMN, pkColumnName);
                Column col = columnsByIdentifier.get(colName);
                Column refCol = refTable.getColumn(refColName);
                if (col != null && refCol != null) {
                    fk.addColumn(col, refCol);
                } else {
                // TODO throw exception?
                }
            } else {
                NucleusLogger.DATASTORE_SCHEMA.warn("Retrieved ForeignKey from datastore for table=" + toString() + " referencing table " + pkTableName + " but not found internally. Is there some catalog/schema or quoting causing problems?");
            }
        }
    }
    return foreignKeysByName;
}
Also used : HashMap(java.util.HashMap) RDBMSTableFKInfo(org.datanucleus.store.rdbms.schema.RDBMSTableFKInfo) StoreSchemaHandler(org.datanucleus.store.schema.StoreSchemaHandler) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory) ForeignKeyInfo(org.datanucleus.store.rdbms.schema.ForeignKeyInfo) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) Iterator(java.util.Iterator)

Example 10 with ForeignKey

use of org.datanucleus.store.rdbms.key.ForeignKey in project datanucleus-rdbms by datanucleus.

the class TableUtils method getForeignKeyForPCField.

/**
 * Convenience method to add a foreign key for a PC field.
 * Adds a FK from the PC column(s) in this table to the ID columns in the PC's table.
 * @param fieldMapping Mapping for the PC field
 * @param mmd MetaData for the field
 * @param autoMode Whether we are in auto-create mode
 * @param storeMgr Store Manager
 * @param clr ClassLoader resolver
 * @return The ForeignKey (if any)
 */
public static ForeignKey getForeignKeyForPCField(JavaTypeMapping fieldMapping, AbstractMemberMetaData mmd, boolean autoMode, RDBMSStoreManager storeMgr, ClassLoaderResolver clr) {
    DatastoreClass referencedTable = storeMgr.getDatastoreClass(mmd.getTypeName(), clr);
    if (referencedTable == null) {
        // PC type uses subclass-table
        AbstractClassMetaData refCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getType(), clr);
        if (refCmd != null) {
            AbstractClassMetaData[] refCmds = storeMgr.getClassesManagingTableForClass(refCmd, clr);
            if (refCmds != null && refCmds.length == 1) {
                referencedTable = storeMgr.getDatastoreClass(refCmds[0].getFullClassName(), clr);
            } else {
            // "subclass-table" with more than 1 subclass with table (not supported)
            }
        }
    }
    if (referencedTable != null) {
        ForeignKeyMetaData fkmd = mmd.getForeignKeyMetaData();
        if ((fkmd != null && (fkmd.getDeleteAction() != ForeignKeyAction.NONE || fkmd.getFkDefinitionApplies())) || autoMode) {
            // Either has been specified by user, or using autoMode, so add FK
            ForeignKey fk = new ForeignKey(fieldMapping, storeMgr.getDatastoreAdapter(), referencedTable, true);
            // Does nothing when no FK MetaData
            fk.setForMetaData(fkmd);
            if (fkmd != null && fkmd.getName() != null) {
                fk.setName(fkmd.getName());
            }
            return fk;
        }
    }
    return null;
}
Also used : ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Aggregations

ForeignKey (org.datanucleus.store.rdbms.key.ForeignKey)18 ArrayList (java.util.ArrayList)9 ForeignKeyMetaData (org.datanucleus.metadata.ForeignKeyMetaData)9 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)6 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)5 ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)5 Collection (java.util.Collection)4 NoTableManagedException (org.datanucleus.store.rdbms.exceptions.NoTableManagedException)4 PrimaryKey (org.datanucleus.store.rdbms.key.PrimaryKey)4 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)4 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 Iterator (java.util.Iterator)3 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)3 DatastoreIdentifier (org.datanucleus.store.rdbms.identifier.DatastoreIdentifier)3 List (java.util.List)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)2 IdentifierFactory (org.datanucleus.store.rdbms.identifier.IdentifierFactory)2 EmbeddedPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping)2 Column (org.datanucleus.store.rdbms.table.Column)2