Search in sources :

Example 26 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-rdbms by datanucleus.

the class PersistableMapping method setObjectAsValue.

/**
 * Method to set an object reference (FK) in the datastore.
 * @param ec The ExecutionContext
 * @param ps The Prepared Statement
 * @param param The parameter ids in the statement
 * @param value The value to put in the statement at these ids
 * @param ownerSM StateManager for the owner object
 * @param ownerFieldNumber Field number of this PC object in the owner
 * @throws NotYetFlushedException Just put "null" in and throw "NotYetFlushedException", to be caught by ParameterSetter and will signal to the
 *     PC object being inserted that it needs to inform this object when it is inserted.
 */
private void setObjectAsValue(ExecutionContext ec, PreparedStatement ps, int[] param, Object value, DNStateManager ownerSM, int ownerFieldNumber) {
    Object id;
    ApiAdapter api = ec.getApiAdapter();
    if (!api.isPersistable(value)) {
        throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal();
    }
    DNStateManager valueSM = ec.findStateManager(value);
    try {
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        // Check if the field is attributed in the datastore
        boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(ec.getMetaDataManager(), storeMgr, clr);
        boolean inserted = false;
        if (ownerFieldNumber >= 0) {
            // Field mapping : is this field of the related object present in the datastore?
            inserted = storeMgr.isObjectInserted(valueSM, ownerFieldNumber);
        } else if (mmd == null) {
            // Identity mapping : is the object inserted far enough to be considered of this mapping type?
            inserted = storeMgr.isObjectInserted(valueSM, type);
        }
        if (valueSM != null) {
            if (ec.getApiAdapter().isDetached(value) && valueSM.getReferencedPC() != null && ownerSM != null && mmd != null) {
                // Still detached but started attaching so replace the field with what will be the attached
                // Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table
                // mapping
                ownerSM.replaceFieldMakeDirty(ownerFieldNumber, valueSM.getReferencedPC());
            }
            if (valueSM.isWaitingToBeFlushedToDatastore()) {
                try {
                    // Related object is not yet flushed to the datastore so flush it so we can set the FK
                    valueSM.flush();
                } catch (NotYetFlushedException nfe) {
                    // Could not flush it, maybe it has a relation to this object! so set as null TODO check nullability
                    if (ownerSM != null) {
                        ownerSM.updateFieldAfterInsert(value, ownerFieldNumber);
                    }
                    setObjectAsNull(ec, ps, param);
                    return;
                }
            }
        } else {
            if (ec.getApiAdapter().isDetached(value)) {
                // Field value is detached and not yet started attaching, so attach
                Object attachedValue = ec.persistObjectInternal(value, null, -1, PersistableObjectType.PC);
                if (attachedValue != value && ownerSM != null) {
                    // Replace the field value if using copy-on-attach
                    ownerSM.replaceFieldMakeDirty(ownerFieldNumber, attachedValue);
                    // Work from attached value now that it is attached
                    value = attachedValue;
                }
                valueSM = ec.findStateManager(value);
            }
        }
        // 5) the value is the same object as we are inserting anyway and has its identity set
        if (inserted || !ec.isInserting(value) || (!hasDatastoreAttributedPrimaryKeyValues && (this.mmd != null && this.mmd.isPrimaryKey())) || (!hasDatastoreAttributedPrimaryKeyValues && ownerSM == valueSM && api.getIdForObject(value) != null)) {
            // The PC is either already inserted, or inserted down to the level we need, or not inserted at all,
            // or the field is a PK and identity not attributed by the datastore
            // Object either already exists, or is not yet being inserted.
            id = api.getIdForObject(value);
            // Check if the persistable object exists in this datastore
            boolean requiresPersisting = false;
            if (ec.getApiAdapter().isDetached(value) && ownerSM != null) {
                // Detached object so needs attaching
                if (ownerSM.isInserting()) {
                    // we can just return the value now and attach later (in InsertRequest)
                    if (!ec.getBooleanProperty(PropertyNames.PROPERTY_ATTACH_SAME_DATASTORE)) {
                        if (ec.getObjectFromCache(api.getIdForObject(value)) != null) {
                        // Object is in cache so exists for this datastore, so no point checking
                        } else {
                            try {
                                Object obj = ec.findObject(api.getIdForObject(value), true, false, value.getClass().getName());
                                if (obj != null) {
                                    // Make sure this object is not retained in cache etc
                                    DNStateManager sm = ec.findStateManager(obj);
                                    if (sm != null) {
                                        ec.evictFromTransaction(sm);
                                    }
                                    ec.removeObjectFromLevel1Cache(api.getIdForObject(value));
                                }
                            } catch (NucleusObjectNotFoundException onfe) {
                                // Object doesn't yet exist
                                requiresPersisting = true;
                            }
                        }
                    }
                } else {
                    requiresPersisting = true;
                }
            } else if (id == null) {
                // Transient object, so we need to persist it
                requiresPersisting = true;
            } else {
                ExecutionContext pcEC = ec.getApiAdapter().getExecutionContext(value);
                if (pcEC != null && ec != pcEC) {
                    throw new NucleusUserException(Localiser.msg("041015"), id);
                }
            }
            if (requiresPersisting) {
                // This PC object needs persisting (new or detached) to do the "set"
                if (mmd != null && !mmd.isCascadePersist() && !ec.getApiAdapter().isDetached(value)) {
                    // Related PC object not persistent, but cant do cascade-persist so throw exception
                    if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                        NucleusLogger.PERSISTENCE.debug(Localiser.msg("007006", mmd.getFullFieldName()));
                    }
                    throw new ReachableObjectNotCascadedException(mmd.getFullFieldName(), value);
                }
                if (NucleusLogger.PERSISTENCE.isDebugEnabled()) {
                    NucleusLogger.PERSISTENCE.debug(Localiser.msg("007007", ownerSM != null ? IdentityUtils.getPersistableIdentityForId(ownerSM.getInternalObjectId()) : id, mmd != null ? mmd.getFullFieldName() : null));
                }
                try {
                    Object pcNew = ec.persistObjectInternal(value, null, -1, PersistableObjectType.PC);
                    if (hasDatastoreAttributedPrimaryKeyValues) {
                        ec.flushInternal(false);
                    }
                    id = api.getIdForObject(pcNew);
                    if (ec.getApiAdapter().isDetached(value) && ownerSM != null && mmd != null) {
                        // Update any detached reference to refer to the attached variant
                        ownerSM.replaceFieldMakeDirty(ownerFieldNumber, pcNew);
                        RelationType relationType = mmd.getRelationType(clr);
                        if (relationType == RelationType.MANY_TO_ONE_BI) {
                            // TODO Update the container to refer to the attached object
                            if (NucleusLogger.PERSISTENCE.isInfoEnabled()) {
                                NucleusLogger.PERSISTENCE.info("PCMapping.setObject : object " + ownerSM.getInternalObjectId() + " has field " + ownerFieldNumber + " that is 1-N bidirectional." + " Have just attached the N side so should really update the reference in the 1 side collection" + " to refer to this attached object. Not yet implemented");
                            }
                        } else if (relationType == RelationType.ONE_TO_ONE_BI) {
                            AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                            // TODO Cater for more than 1 related field
                            DNStateManager relatedSM = ec.findStateManager(pcNew);
                            relatedSM.replaceFieldMakeDirty(relatedMmds[0].getAbsoluteFieldNumber(), ownerSM.getObject());
                        }
                    }
                } catch (NotYetFlushedException e) {
                    setObjectAsNull(ec, ps, param);
                    throw new NotYetFlushedException(value);
                }
            }
            if (valueSM != null) {
                valueSM.setStoringPC();
            }
            // If the field doesn't map to any columns (e.g remote FK), omit the set process
            if (getNumberOfColumnMappings() > 0) {
                if (IdentityUtils.isDatastoreIdentity(id)) {
                    Object idKey = IdentityUtils.getTargetKeyForDatastoreIdentity(id);
                    try {
                        // Try as a Long
                        getColumnMapping(0).setObject(ps, param[0], idKey);
                    } catch (Exception e) {
                        // Must be a String
                        getColumnMapping(0).setObject(ps, param[0], idKey.toString());
                    }
                } else {
                    boolean fieldsSet = false;
                    if (IdentityUtils.isSingleFieldIdentity(id) && javaTypeMappings.length > 1) {
                        Object key = IdentityUtils.getTargetKeyForSingleFieldIdentity(id);
                        AbstractClassMetaData keyCmd = ec.getMetaDataManager().getMetaDataForClass(key.getClass(), clr);
                        if (keyCmd != null && keyCmd.getIdentityType() == IdentityType.NONDURABLE) {
                            // Embedded ID - Make sure these are called starting at lowest first, in order
                            // We cannot just call SM.provideFields with all fields since that does last first
                            DNStateManager keySM = ec.findStateManager(key);
                            int[] fieldNums = keyCmd.getAllMemberPositions();
                            FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                            for (int i = 0; i < fieldNums.length; i++) {
                                keySM.provideFields(new int[] { fieldNums[i] }, fm);
                            }
                            fieldsSet = true;
                        }
                    }
                    if (!fieldsSet) {
                        // Copy PK fields from identity to the object
                        FieldManager fm = new AppIDObjectIdFieldManager(param, ec, ps, javaTypeMappings);
                        api.copyKeyFieldsFromIdToObject(value, new AppIdObjectIdFieldConsumer(api, fm), id);
                    }
                }
            }
        } else {
            if (valueSM != null) {
                valueSM.setStoringPC();
            }
            if (getNumberOfColumnMappings() > 0) {
                // Object is in the process of being inserted so we cant use its id currently and we need to store
                // a foreign key to it (which we cant yet do). Just put "null" in and throw "NotYetFlushedException",
                // to be caught by ParameterSetter and will signal to the PC object being inserted that it needs
                // to inform this object when it is inserted.
                setObjectAsNull(ec, ps, param);
                throw new NotYetFlushedException(value);
            }
        }
    } finally {
        if (valueSM != null) {
            valueSM.unsetStoringPC();
        }
    }
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) SingleValueFieldManager(org.datanucleus.store.fieldmanager.SingleValueFieldManager) FieldManager(org.datanucleus.store.fieldmanager.FieldManager) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) NucleusException(org.datanucleus.exceptions.NucleusException) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) NotYetFlushedException(org.datanucleus.exceptions.NotYetFlushedException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReachableObjectNotCascadedException(org.datanucleus.exceptions.ReachableObjectNotCascadedException) ExecutionContext(org.datanucleus.ExecutionContext) RelationType(org.datanucleus.metadata.RelationType) AppIDObjectIdFieldManager(org.datanucleus.store.rdbms.mapping.AppIDObjectIdFieldManager) DNStateManager(org.datanucleus.state.DNStateManager) NucleusException(org.datanucleus.exceptions.NucleusException) AppIdObjectIdFieldConsumer(org.datanucleus.state.AppIdObjectIdFieldConsumer)

Example 27 with NucleusObjectNotFoundException

use of org.datanucleus.exceptions.NucleusObjectNotFoundException in project datanucleus-rdbms by datanucleus.

the class OracleClobColumnMapping method setPostProcessing.

@SuppressWarnings("deprecation")
@Override
public void setPostProcessing(DNStateManager sm, Object value) {
    String stringValue = (String) value;
    ExecutionContext ec = sm.getExecutionContext();
    Table table = column.getTable();
    RDBMSStoreManager storeMgr = table.getStoreManager();
    if (table instanceof DatastoreClass) {
        // CLOB within a primary table
        DatastoreClass classTable = (DatastoreClass) table;
        // Generate "SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE" statement
        SelectStatement sqlStmt = new SelectStatement(storeMgr, table, null, null);
        sqlStmt.setClassLoaderResolver(ec.getClassLoaderResolver());
        sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
        SQLTable blobSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), mapping);
        sqlStmt.select(blobSqlTbl, column, null);
        StatementClassMapping mappingDefinition = new StatementClassMapping();
        AbstractClassMetaData cmd = sm.getClassMetaData();
        SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
        int inputParamNum = 1;
        if (cmd.getIdentityType() == IdentityType.DATASTORE) {
            // Datastore identity value for input
            JavaTypeMapping datastoreIdMapping = classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
            SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), datastoreIdMapping);
            SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, datastoreIdMapping, null, "ID");
            sqlStmt.whereAnd(expr.eq(val), true);
            StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
            if (datastoreIdx == null) {
                datastoreIdx = new StatementMappingIndex(datastoreIdMapping);
                mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdx);
            }
            datastoreIdx.addParameterOccurrence(new int[] { inputParamNum });
        } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
            // Application identity value(s) for input
            int[] pkNums = cmd.getPKMemberPositions();
            for (int i = 0; i < pkNums.length; i++) {
                AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[i]);
                JavaTypeMapping pkMapping = classTable.getMemberMapping(mmd);
                SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), pkMapping);
                SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, pkMapping, null, "PK" + i);
                sqlStmt.whereAnd(expr.eq(val), true);
                StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNums[i]);
                if (pkIdx == null) {
                    pkIdx = new StatementMappingIndex(pkMapping);
                    mappingDefinition.addMappingForMember(pkNums[i], pkIdx);
                }
                int[] inputParams = new int[pkMapping.getNumberOfColumnMappings()];
                for (int j = 0; j < pkMapping.getNumberOfColumnMappings(); j++) {
                    inputParams[j] = inputParamNum++;
                }
                pkIdx.addParameterOccurrence(inputParams);
            }
        }
        String textStmt = sqlStmt.getSQLText().toSQL();
        if (sm.isEmbedded()) {
            // This mapping is embedded, so navigate back to the real owner since that is the "id" in the table
            DNStateManager embeddedOwner = ec.getOwnerForEmbeddedStateManager(sm);
            if (embeddedOwner != null) {
                // TODO Should check if the owner is stored in this table
                sm = embeddedOwner;
            }
        }
        try {
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try {
                PreparedStatement ps = sqlControl.getStatementForQuery(mconn, textStmt);
                try {
                    // Provide the primary key field(s) to the JDBC statement
                    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                        StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
                        for (int i = 0; i < datastoreIdx.getNumberOfParameterOccurrences(); i++) {
                            classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(i), sm.getInternalObjectId());
                        }
                    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                        sm.provideFields(cmd.getPKMemberPositions(), new ParameterSetter(sm, ps, mappingDefinition));
                    }
                    ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, textStmt, ps);
                    try {
                        if (!rs.next()) {
                            throw new NucleusObjectNotFoundException(Localiser.msg("050018", IdentityUtils.getPersistableIdentityForId(sm.getInternalObjectId())));
                        }
                        DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
                        int jdbcMajorVersion = dba.getDriverMajorVersion();
                        if (dba.getDatastoreDriverName().equalsIgnoreCase(OracleAdapter.OJDBC_DRIVER_NAME) && jdbcMajorVersion < 10) {
                            // Oracle JDBC drivers version 9 and below use some sh*tty Oracle-specific CLOB type
                            oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob(1);
                            if (clob != null) {
                                // Deprecated but what can you do
                                clob.putString(1, stringValue);
                            }
                        } else {
                            // Oracle JDBC drivers 10 and above supposedly use the JDBC standard class for Clobs
                            java.sql.Clob clob = rs.getClob(1);
                            if (clob != null) {
                                clob.setString(1, stringValue);
                            }
                        }
                    } finally {
                        rs.close();
                    }
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException e) {
            throw new NucleusDataStoreException("Update of CLOB value failed: " + textStmt, e);
        }
    } else {
        // TODO Support join table
        throw new NucleusDataStoreException("We do not support INSERT/UPDATE CLOB post processing of non-primary table " + table);
    }
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) Table(org.datanucleus.store.rdbms.table.Table) PreparedStatement(java.sql.PreparedStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) ExecutionContext(org.datanucleus.ExecutionContext) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DNStateManager(org.datanucleus.state.DNStateManager) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

NucleusObjectNotFoundException (org.datanucleus.exceptions.NucleusObjectNotFoundException)27 ExecutionContext (org.datanucleus.ExecutionContext)15 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)14 ObjectProvider (org.datanucleus.state.ObjectProvider)12 PreparedStatement (java.sql.PreparedStatement)10 ResultSet (java.sql.ResultSet)10 SQLException (java.sql.SQLException)10 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)10 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)10 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)10 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)10 SQLController (org.datanucleus.store.rdbms.SQLController)10 ParameterSetter (org.datanucleus.store.rdbms.fieldmanager.ParameterSetter)10 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)10 ArrayList (java.util.ArrayList)9 List (java.util.List)8 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)8 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)6 ApiAdapter (org.datanucleus.api.ApiAdapter)6 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)6