{
throw new JPOXException(LOCALISER.msg("041016",
value.getClass(), value)).setFatal();
}
StateManager sm = om.findStateManager(value);
try
{
ClassLoaderResolver clr = om.getClassLoaderResolver();
// Check if the field is attributed in the datastore
boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(
om.getMetaDataManager(), om.getStoreManager(), clr);
boolean inserted = false;
if (ownerFieldNumber >= 0)
{
// Field mapping : is this field of the related object present in the datastore?
inserted = om.isInserted(value, ownerFieldNumber);
}
else if (fmd == null)
{
// Identity mapping : is the object inserted far enough to be considered of this mapping type?
inserted = om.isInserted(value, type);
}
if (sm != null)
{
if (om.getApiAdapter().isDetached(value) && sm.getReferencedPC() != null && ownerSM != null && fmd != null)
{
// 1-1, N-1 mapping
// The value is really still detached but has a temporary StateManager whilst attaching so
// replace this field reference to be for the newly attached object
// Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table
// mapping
ownerSM.replaceField(ownerFieldNumber, sm.getReferencedPC(), true);
}
if (sm.isWaitingToBeFlushedToDatastore())
{
// Related object is not yet flushed to the datastore so flush it so we can set the FK
sm.flush();
}
}
// we can execute this block when
// 1) the pc has been inserted; OR
// 2) is not in process of being inserted; OR
// 3) is being inserted yet is inserted enough to use this mapping; OR
// 4) the PC PK values are not attributed by the database and this mapping is for a PK field (compound identity)
if (inserted || !om.isInserting(value) ||
(!hasDatastoreAttributedPrimaryKeyValues && (this.fmd != null && this.fmd.isPrimaryKey())))
{
// 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 PersistenceCapable exists in this datastore
boolean requiresPersisting = false;
if (om.getApiAdapter().isDetached(value) && ownerSM != null)
{
// Detached object so needs attaching
if (ownerSM.isInserting())
{
// Inserting other object, and this object is detached but if detached from this datastore
// we can just return the value now and attach later (in InsertRequest)
if (!om.getOMFContext().getPersistenceConfiguration().getBooleanProperty("org.jpox.attachSameDatastore"))
{
if (om.getObjectFromCache(api.getIdForObject(value)) != null)
{
// Object is in cache so exists for this datastore, so no point checking
}
else
{
try
{
Object obj = om.findObject(api.getIdForObject(value), true, false,
value.getClass().getName());
if (obj != null)
{
// Make sure this object is not retained in cache etc
StateManager objSM = om.findStateManager(obj);
if (objSM != null)
{
om.evictFromTransaction(objSM);
}
om.removeObjectFromCache(value, api.getIdForObject(value), true, true);
}
}
catch (JPOXObjectNotFoundException onfe)
{
// Object doesnt yet exist
requiresPersisting = true;
}
}
}
}
else
{
requiresPersisting = true;
}
}
else if (id == null)
{
// Transient object, so we need to persist it
requiresPersisting = true;
}
else
{
ObjectManager pcPM = ObjectManagerHelper.getObjectManager(value);
if (pcPM != null && om != pcPM)
{
throw new JPOXUserException(LOCALISER.msg("041015"), id);
}
}
if (requiresPersisting)
{
// PERSISTENCE-BY-REACHABILITY
// This PC object needs persisting (new or detached) to do the "set"
if (fmd != null && !fmd.isCascadePersist() && !om.getApiAdapter().isDetached(value))
{
// Related PC object not persistent, but cant do cascade-persist so throw exception
if (JPOXLogger.REACHABILITY.isDebugEnabled())
{
JPOXLogger.REACHABILITY.debug(LOCALISER.msg("007006",
fmd.getFullFieldName()));
}
throw new ReachableObjectNotCascadedException(fmd.getFullFieldName(), value);
}
if (JPOXLogger.REACHABILITY.isDebugEnabled())
{
JPOXLogger.REACHABILITY.debug(LOCALISER.msg("007007",
fmd != null ? fmd.getFullFieldName() : null));
}
try
{
Object pcNew = om.persistObjectInternal(value, null, null, -1, StateManager.PC);
if (hasDatastoreAttributedPrimaryKeyValues)
{
om.flushInternal(false);
}
id = api.getIdForObject(pcNew);
if (om.getApiAdapter().isDetached(value) && ownerSM != null)
{
// Update any detached reference to refer to the attached variant
ownerSM.replaceField(ownerFieldNumber, pcNew, true);
int relationType = fmd.getRelationType(clr);
if (relationType == Relation.MANY_TO_ONE_BI)
{
// TODO Update the container to refer to the attached object
if (JPOXLogger.PERSISTENCE.isInfoEnabled())
{
JPOXLogger.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 == Relation.ONE_TO_ONE_BI)
{
AbstractMemberMetaData[] relatedMmds = fmd.getRelatedMemberMetaData(clr);
// TODO Cater for more than 1 related field
StateManager relatedSM = om.findStateManager(pcNew);
relatedSM.replaceField(relatedMmds[0].getAbsoluteFieldNumber(), ownerSM.getObject(), true);
}
}
}
catch (NotYetFlushedException e)
{