// No relations waiting to be persisted
return false;
}
ObjectProvider op = getObjectProvider();
DatastoreTable table = getDatastoreTable();
if (datastoreEntity.getKey() != null) {
Key key = datastoreEntity.getKey();
AbstractClassMetaData acmd = op.getClassMetaData();
int[] relationFieldNums = acmd.getRelationMemberPositions(ec.getClassLoaderResolver(), ec.getMetaDataManager());
if (relationFieldNums != null) {
for (int i=0;i<relationFieldNums.length;i++) {
AbstractMemberMetaData mmd = acmd.getMetaDataForManagedMemberAtAbsolutePosition(relationFieldNums[i]);
boolean owned = MetaDataUtils.isOwnedRelation(mmd, getStoreManager());
if (owned) {
// Register parent key for all owned related objects
Object childValue = op.provideField(mmd.getAbsoluteFieldNumber());
if (childValue != null) {
if (childValue instanceof Object[]) {
childValue = Arrays.asList((Object[]) childValue);
}
String expectedType = mmd.getTypeName();
if (mmd.getCollection() != null) {
CollectionMetaData cmd = mmd.getCollection();
expectedType = cmd.getElementType();
} else if (mmd.getArray() != null) {
ArrayMetaData amd = mmd.getArray();
expectedType = amd.getElementType();
}
if (childValue instanceof Iterable) {
// TODO(maxr): Make sure we're not pulling back unnecessary data when we iterate over the values.
for (Object element : (Iterable) childValue) {
addToParentKeyMap(keyRegistry, element, key, ec, expectedType, true);
}
} else if (childValue.getClass().isArray()) {
for (int j=0;j<Array.getLength(childValue);i++) {
addToParentKeyMap(keyRegistry, Array.get(childValue, i), key, ec, expectedType, true);
}
} else if (childValue instanceof Map) {
boolean persistableKey = (mmd.getMap().getKeyClassMetaData(ec.getClassLoaderResolver(), ec.getMetaDataManager()) != null);
boolean persistableVal = (mmd.getMap().getValueClassMetaData(ec.getClassLoaderResolver(), ec.getMetaDataManager()) != null);
Iterator entryIter = ((Map)childValue).entrySet().iterator();
while (entryIter.hasNext()) {
Map.Entry entry = (Map.Entry)entryIter.next();
if (persistableKey) {
addToParentKeyMap(keyRegistry, entry.getKey(), key, ec, expectedType, true);
}
if (persistableVal) {
addToParentKeyMap(keyRegistry, entry.getValue(), key, ec, expectedType, true);
}
}
} else {
addToParentKeyMap(keyRegistry, childValue, key, ec, expectedType,
!table.isParentKeyProvider(mmd));
}
}
} else {
// Register that related object(s) is unowned
Object childValue = op.provideField(mmd.getAbsoluteFieldNumber());
if (childValue != null) {
if (childValue instanceof Object[]) {
childValue = Arrays.asList((Object[]) childValue);
}
if (childValue instanceof Iterable) {
// TODO(maxr): Make sure we're not pulling back unnecessary data when we iterate over the values.
for (Object element : (Iterable) childValue) {
keyRegistry.registerUnownedObject(element);
}
} else {
keyRegistry.registerUnownedObject(childValue);
}
}
}
}
}
}
boolean modifiedEntity = false;
// Stage 1 : process FKs
for (RelationStoreInformation relInfo : relationStoreInfos) {
AbstractMemberMetaData mmd = relInfo.mmd;
try {
JavaTypeMapping mapping = table.getMemberMappingInDatastoreClass(relInfo.mmd);
if (mapping instanceof EmbeddedPCMapping ||
mapping instanceof SerialisedPCMapping ||
mapping instanceof SerialisedReferenceMapping ||
mapping instanceof PersistableMapping ||
mapping instanceof InterfaceMapping) {
boolean owned = MetaDataUtils.isOwnedRelation(mmd, getStoreManager());
RelationType relationType = mmd.getRelationType(ec.getClassLoaderResolver());
if (owned) {
// Owned relation
boolean owner = false;
if (relationType == RelationType.ONE_TO_ONE_UNI || relationType == RelationType.ONE_TO_MANY_UNI ||
relationType == RelationType.ONE_TO_MANY_BI) {
owner = true;
} else if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null) {
owner = true;
}
if (!table.isParentKeyProvider(mmd)) {
// Make sure the parent key is set properly between parent and child objects
if (!owner) {
ObjectProvider parentOP = ec.findObjectProvider(relInfo.value);
EntityUtils.checkParentage(op.getObject(), parentOP);
} else {
EntityUtils.checkParentage(relInfo.value, op);
}
mapping.setObject(ec, datastoreEntity, IS_FK_VALUE_ARR, relInfo.value, op, mmd.getAbsoluteFieldNumber());
}
} else {
// Unowned relation
mapping.setObject(ec, datastoreEntity, IS_FK_VALUE_ARR, relInfo.value, op, mmd.getAbsoluteFieldNumber());
}
}
} catch (NotYetFlushedException e) {
// Ignore this. We always have the object in the datastore, at least partially to get the key
}
}
// Stage 2 : postInsert/postUpdate
for (RelationStoreInformation relInfo : relationStoreInfos) {
try {
JavaTypeMapping mapping = table.getMemberMappingInDatastoreClass(relInfo.mmd);
if (mapping instanceof ArrayMapping || mapping instanceof MapMapping) {
// Ignore postInsert/update for arrays/maps since don't support backing stores
} else if (mapping instanceof MappingCallbacks) {
if (insert) {
((MappingCallbacks)mapping).postInsert(op);