Search in sources :

Example 16 with ForeignKeyMetaData

use of org.datanucleus.metadata.ForeignKeyMetaData 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 17 with ForeignKeyMetaData

use of org.datanucleus.metadata.ForeignKeyMetaData 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)

Example 18 with ForeignKeyMetaData

use of org.datanucleus.metadata.ForeignKeyMetaData in project datanucleus-rdbms by datanucleus.

the class DeleteRequest method updateOneToOneBidirectionalOwnerObjectForField.

/**
 * Method to update any 1-1 bidir non-owner fields where the foreign-key is stored in the other object.
 * @param op ObjectProvider of this object
 * @param mmd MetaData for field that has related (owner) objects
 */
private void updateOneToOneBidirectionalOwnerObjectForField(ObjectProvider op, AbstractMemberMetaData fmd) {
    if (softDeleteStmt != null) {
        // If we are soft deleting the owner then no need to null the linkage BUT we need to check the soft delete status on retrieval of the owner from related
        return;
    }
    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
        NucleusLogger.PERSISTENCE.debug(Localiser.msg("052217", op.getObjectAsPrintable(), fmd.getFullFieldName()));
    }
    RDBMSStoreManager storeMgr = table.getStoreManager();
    ExecutionContext ec = op.getExecutionContext();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
    // Check if we should null here, or leave to the datastore FK handler
    boolean checkFK = true;
    if (ec.getStringProperty(PropertyNames.PROPERTY_DELETION_POLICY).equals("JDO2")) {
        // JDO2 doesn't currently (2.0 spec) take note of foreign-key
        checkFK = false;
    }
    if (checkFK) {
        for (int i = 0; i < relatedMmds.length; i++) {
            ForeignKeyMetaData relFkmd = relatedMmds[i].getForeignKeyMetaData();
            if (relFkmd != null && relFkmd.getDeleteAction() != null) {
                // Field has a FK with a delete-action so leave to the datastore to process the delete
                return;
            }
        }
    }
    // TODO Cater for more than 1 related field
    String fullClassName = ((AbstractClassMetaData) relatedMmds[0].getParent()).getFullClassName();
    // TODO I'm not sure that we need to loop all implementations. will we have the fk set to all tables, if many?
    String[] classes;
    if (((AbstractClassMetaData) relatedMmds[0].getParent()) instanceof InterfaceMetaData) {
        classes = storeMgr.getNucleusContext().getMetaDataManager().getClassesImplementingInterface(fullClassName, clr);
    } else {
        classes = new String[] { fullClassName };
    }
    Set<DatastoreClass> datastoreClasses = new HashSet();
    for (int i = 0; i < classes.length; i++) {
        // just remove duplicates
        datastoreClasses.add(storeMgr.getDatastoreClass(classes[i], clr));
    }
    Iterator<DatastoreClass> it = datastoreClasses.iterator();
    while (it.hasNext()) {
        DatastoreClass refTable = it.next();
        JavaTypeMapping refMapping = refTable.getMemberMapping(fmd.getMappedBy());
        if (// Only clear the references that can be cleared
        refMapping.isNullable()) {
            // Create a statement to clear the link from the previous related object
            StringBuilder clearLinkStmt = new StringBuilder("UPDATE " + refTable.toString() + " SET ");
            for (int j = 0; j < refMapping.getNumberOfDatastoreMappings(); j++) {
                if (j > 0) {
                    clearLinkStmt.append(",");
                }
                clearLinkStmt.append(refMapping.getDatastoreMapping(j).getColumn().getIdentifier());
                clearLinkStmt.append("=NULL");
            }
            clearLinkStmt.append(" WHERE ");
            for (int j = 0; j < refMapping.getNumberOfDatastoreMappings(); j++) {
                if (j > 0) {
                    clearLinkStmt.append(" AND ");
                }
                clearLinkStmt.append(refMapping.getDatastoreMapping(j).getColumn().getIdentifier());
                clearLinkStmt.append("=?");
            }
            try {
                ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
                SQLController sqlControl = storeMgr.getSQLController();
                try {
                    // Null out the relationship to the object being deleted.
                    PreparedStatement ps = null;
                    try {
                        ps = sqlControl.getStatementForUpdate(mconn, clearLinkStmt.toString(), false);
                        refMapping.setObject(ec, ps, MappingHelper.getMappingIndices(1, refMapping), op.getObject());
                        sqlControl.executeStatementUpdate(ec, mconn, clearLinkStmt.toString(), ps, true);
                    } finally {
                        if (ps != null) {
                            sqlControl.closeStatement(mconn, ps);
                        }
                    }
                } finally {
                    mconn.release();
                }
            } catch (Exception e) {
                throw new NucleusDataStoreException("Update request failed", e);
            }
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PreparedStatement(java.sql.PreparedStatement) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLException(java.sql.SQLException) NucleusException(org.datanucleus.exceptions.NucleusException) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) NucleusOptimisticException(org.datanucleus.exceptions.NucleusOptimisticException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ExecutionContext(org.datanucleus.ExecutionContext) ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData) InterfaceMetaData(org.datanucleus.metadata.InterfaceMetaData) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) HashSet(java.util.HashSet)

Example 19 with ForeignKeyMetaData

use of org.datanucleus.metadata.ForeignKeyMetaData in project datanucleus-api-jdo by datanucleus.

the class KeyMetadataImpl method getForeignKeyMetadata.

/* (non-Javadoc)
     * @see javax.jdo.metadata.KeyMetadata#getForeignKeyMetadata()
     */
public ForeignKeyMetadata getForeignKeyMetadata() {
    ForeignKeyMetaData internalFkmd = getInternal().getForeignKeyMetaData();
    if (internalFkmd == null) {
        return null;
    }
    ForeignKeyMetadataImpl fkmd = new ForeignKeyMetadataImpl(internalFkmd);
    fkmd.parent = this;
    return fkmd;
}
Also used : ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData)

Example 20 with ForeignKeyMetaData

use of org.datanucleus.metadata.ForeignKeyMetaData in project datanucleus-api-jdo by datanucleus.

the class MemberMetadataImpl method getForeignKeyMetadata.

public ForeignKeyMetadata getForeignKeyMetadata() {
    ForeignKeyMetaData internalFkmd = getInternal().getForeignKeyMetaData();
    if (internalFkmd == null) {
        return null;
    }
    ForeignKeyMetadataImpl fkmd = new ForeignKeyMetadataImpl(internalFkmd);
    fkmd.parent = this;
    return fkmd;
}
Also used : ForeignKeyMetaData(org.datanucleus.metadata.ForeignKeyMetaData)

Aggregations

ForeignKeyMetaData (org.datanucleus.metadata.ForeignKeyMetaData)26 ForeignKey (org.datanucleus.store.rdbms.key.ForeignKey)8 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)6 ArrayList (java.util.ArrayList)5 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)5 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)5 DiscriminatorMetaData (org.datanucleus.metadata.DiscriminatorMetaData)3 FetchGroupMetaData (org.datanucleus.metadata.FetchGroupMetaData)3 IndexMetaData (org.datanucleus.metadata.IndexMetaData)3 JoinMetaData (org.datanucleus.metadata.JoinMetaData)3 UniqueMetaData (org.datanucleus.metadata.UniqueMetaData)3 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)3 Collection (java.util.Collection)2 HashSet (java.util.HashSet)2 AttributeConverter (javax.jdo.AttributeConverter)2 Column (javax.jdo.annotations.Column)2 Extension (javax.jdo.annotations.Extension)2 ForeignKeyAction (javax.jdo.annotations.ForeignKeyAction)2 Persistent (javax.jdo.annotations.Persistent)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)2