OPENJPA-1253: support non-default bi-directional one-to-many using foreign key strategy to find/query from the ower's side

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@817831 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Fay Wang 2009-09-22 20:38:36 +00:00
parent 01c26a9e21
commit 6f1b9627fe
2 changed files with 88 additions and 31 deletions

View File

@ -83,8 +83,10 @@ public class RelationFieldStrategy
(RelationFieldStrategy.class); (RelationFieldStrategy.class);
private Boolean _fkOid = null; private Boolean _fkOid = null;
boolean _isBiOneToManyJoinTable = false; private int _biOneToManyJoinTable = -1;
private ForeignKey _biOneToManyJoinFK = null;
private ForeignKey _biOneToManyElemFK = null;
public void map(boolean adapt) { public void map(boolean adapt) {
if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC()) if (field.getTypeCode() != JavaTypes.PC || field.isEmbeddedPC())
throw new MetaDataException(_loc.get("not-relation", field)); throw new MetaDataException(_loc.get("not-relation", field));
@ -140,25 +142,8 @@ public class RelationFieldStrategy
OpenJPAConfiguration conf = field.getRepository().getConfiguration(); OpenJPAConfiguration conf = field.getRepository().getConfiguration();
boolean isNonDefaultMappingAllowed = field.getRepository(). boolean isNonDefaultMappingAllowed = field.getRepository().
getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf); getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf);
if (isNonDefaultMappingAllowed) { if (isNonDefaultMappingAllowed)
ClassMapping inverse = field.getValueMapping().getTypeMapping(); getBiOneToManyInfo();
FieldMapping[] fmds = inverse.getFieldMappings();
for (int i = 0; i < fmds.length; i++) {
if (field == fmds[i].getMappedByMapping()) {
int typeCode = fmds[i].getDeclaredTypeCode();
if (typeCode == JavaTypes.ARRAY ||
typeCode == JavaTypes.COLLECTION ||
typeCode == JavaTypes.MAP) {
// this is a bi-directional oneToMany relation with
// @JoinTable annotation ==> join table strategy
// ==> should not mapped in the owner's table
FieldMappingInfo info = fmds[i].getMappingInfo();
_isBiOneToManyJoinTable = (info.getTableName() != null ? true : false);
}
break;
}
}
}
} }
// this is necessary to support openjpa 3 mappings, which didn't // this is necessary to support openjpa 3 mappings, which didn't
@ -183,7 +168,7 @@ public class RelationFieldStrategy
if (field.getMappedByIdValue() != null) if (field.getMappedByIdValue() != null)
setMappedByIdColumns(); setMappedByIdColumns();
if (!_isBiOneToManyJoinTable) { if (_biOneToManyJoinTable == -1) {
ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true, ForeignKey fk = vinfo.getTypeJoin(field, field.getName(), true,
adapt); adapt);
field.setForeignKey(fk); field.setForeignKey(fk);
@ -295,7 +280,7 @@ public class RelationFieldStrategy
else { else {
Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT); Row row = field.getRow(sm, store, rm, Row.ACTION_INSERT);
if (row != null) { if (row != null) {
if (!_isBiOneToManyJoinTable) if (_biOneToManyJoinTable == -1)
field.setForeignKey(row, rel); field.setForeignKey(row, rel);
// this is for bi-directional maps, the key and value of the // this is for bi-directional maps, the key and value of the
// map are stored in the table of the mapped-by entity // map are stored in the table of the mapped-by entity
@ -382,12 +367,29 @@ public class RelationFieldStrategy
Row.ACTION_DELETE : Row.ACTION_UPDATE; Row.ACTION_DELETE : Row.ACTION_UPDATE;
Row row = field.getRow(sm, store, rm, action); Row row = field.getRow(sm, store, rm, action);
if (row != null) { if (row != null) {
if (!_isBiOneToManyJoinTable) if (_biOneToManyJoinTable == -1)
field.setForeignKey(row, rel); field.setForeignKey(row, rel);
// this is for bi-directional maps, the key and value of the // this is for bi-directional maps, the key and value of the
// map are stored in the table of the mapped-by entity // map are stored in the table of the mapped-by entity
setMapKey(sm, rel, store, row); setMapKey(sm, rel, store, row);
} }
if (_biOneToManyJoinTable != -1) { // also need to update the join table
PersistenceCapable inversePC = (PersistenceCapable)sm.fetchObject(_biOneToManyJoinTable);
Row secondaryRow = null;
if (inversePC != null) {
secondaryRow = rm.getSecondaryRow(_biOneToManyJoinFK.getTable(),
Row.ACTION_INSERT);
secondaryRow.setForeignKey(_biOneToManyElemFK, null, sm);
secondaryRow.setForeignKey(_biOneToManyJoinFK, null,
(OpenJPAStateManager)inversePC.pcGetStateManager());
} else {
secondaryRow = rm.getSecondaryRow(_biOneToManyJoinFK.getTable(),
Row.ACTION_DELETE);
secondaryRow.setForeignKey(_biOneToManyElemFK, null, sm);
}
rm.flushSecondaryRow(secondaryRow);
}
} }
} }
@ -560,6 +562,8 @@ public class RelationFieldStrategy
*/ */
private void selectEagerParallel(Select sel, ClassMapping cls, private void selectEagerParallel(Select sel, ClassMapping cls,
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
if (_biOneToManyJoinTable != -1)
return;
sel.selectPrimaryKey(field.getDefiningMapping()); sel.selectPrimaryKey(field.getDefiningMapping());
// set a variable name that does not conflict with any in the query; // set a variable name that does not conflict with any in the query;
// using a variable guarantees that the selected data will use different // using a variable guarantees that the selected data will use different
@ -573,7 +577,7 @@ public class RelationFieldStrategy
public void selectEagerJoin(Select sel, OpenJPAStateManager sm, public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) { JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
if (_isBiOneToManyJoinTable) if (_biOneToManyJoinTable != -1)
return; return;
// limit the eager mode to single on recursive eager fetching b/c // limit the eager mode to single on recursive eager fetching b/c
@ -678,6 +682,8 @@ public class RelationFieldStrategy
public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store, public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, Result res) JDBCFetchConfiguration fetch, Result res)
throws SQLException { throws SQLException {
if (_biOneToManyJoinTable != -1)
return;
ClassMapping cls = field.getIndependentTypeMappings()[0]; ClassMapping cls = field.getIndependentTypeMappings()[0];
// for inverseEager field // for inverseEager field
@ -725,7 +731,7 @@ public class RelationFieldStrategy
// get the related object's oid // get the related object's oid
ClassMapping relMapping = field.getTypeMapping(); ClassMapping relMapping = field.getTypeMapping();
Object oid = null; Object oid = null;
if (relMapping.isMapped() && !_isBiOneToManyJoinTable) { if (relMapping.isMapped() && _biOneToManyJoinTable == -1) {
oid = relMapping.getObjectId(store, res, field.getForeignKey(), oid = relMapping.getObjectId(store, res, field.getForeignKey(),
field.getPolymorphic() != ValueMapping.POLY_FALSE, null); field.getPolymorphic() != ValueMapping.POLY_FALSE, null);
} else { } else {
@ -791,10 +797,18 @@ public class RelationFieldStrategy
sel.whereForeignKey(field.getForeignKey(rels[idx]), sel.whereForeignKey(field.getForeignKey(rels[idx]),
sm.getObjectId(), field.getDefiningMapping(), store); sm.getObjectId(), field.getDefiningMapping(), store);
else { else {
resJoins[idx] = sel.newJoins().joinRelation(field.getName(), if (_biOneToManyJoinTable == -1) {
field.getForeignKey(rels[idx]), rels[idx], resJoins[idx] = sel.newJoins().joinRelation(field.getName(),
field.getSelectSubclasses(), false, false); field.getForeignKey(rels[idx]), rels[idx],
field.wherePrimaryKey(sel, sm, store); field.getSelectSubclasses(), false, false);
field.wherePrimaryKey(sel, sm, store);
} else {
resJoins[idx] = sel.newJoins().joinRelation(null,
getBiOneToManyJoinFK(), rels[idx],
field.getSelectSubclasses(), false, false);
sel.whereForeignKey(getBiOneToManyElemFK(), sm.getObjectId(),
field.getDefiningMapping(), store);
}
} }
sel.select(rels[idx], subs, store, fetch, fetch.EAGER_JOIN, sel.select(rels[idx], subs, store, fetch, fetch.EAGER_JOIN,
resJoins[idx]); resJoins[idx]);
@ -813,6 +827,43 @@ public class RelationFieldStrategy
} }
} }
private ForeignKey getBiOneToManyJoinFK() {
if (_biOneToManyJoinFK == null) {
getBiOneToManyInfo();
}
return _biOneToManyJoinFK;
}
private ForeignKey getBiOneToManyElemFK() {
if (_biOneToManyElemFK == null) {
getBiOneToManyInfo();
}
return _biOneToManyElemFK;
}
private void getBiOneToManyInfo() {
ClassMapping inverse = field.getValueMapping().getTypeMapping();
FieldMapping[] fmds = inverse.getFieldMappings();
for (int i = 0; i < fmds.length; i++) {
if (field == fmds[i].getMappedByMapping()) {
int typeCode = fmds[i].getDeclaredTypeCode();
if (typeCode == JavaTypes.ARRAY ||
typeCode == JavaTypes.COLLECTION ||
typeCode == JavaTypes.MAP) {
// this is a bi-directional oneToMany relation with
// @JoinTable annotation ==> join table strategy
// ==> should not mapped in the owner's table
FieldMappingInfo info = fmds[i].getMappingInfo();
if (info.getTableName() != null)
_biOneToManyJoinTable = i;
_biOneToManyElemFK = fmds[i].getElementMapping().getForeignKey();
_biOneToManyJoinFK = fmds[i].getJoinForeignKey();
}
break;
}
}
}
public Object toDataStoreValue(Object val, JDBCStore store) { public Object toDataStoreValue(Object val, JDBCStore store) {
return RelationStrategies.toDataStoreValue(field, val, store); return RelationStrategies.toDataStoreValue(field, val, store);
} }

View File

@ -369,11 +369,17 @@ extends AbstractCachedEMFTestCase {
em.clear(); em.clear();
//query //query
Query q = em.createQuery("SELECT u FROM Bi_1ToM_JT u"); Query q = em.createQuery("SELECT b FROM Bi_1ToM_JT b where b.name = 'newName'");
Bi_1ToM_JT b1 = (Bi_1ToM_JT)q.getSingleResult(); Bi_1ToM_JT b1 = (Bi_1ToM_JT)q.getSingleResult();
assertEquals(b, b1); assertEquals(b, b1);
em.clear(); em.clear();
//query
q = em.createQuery("SELECT c FROM EntityC_B1MJT c");
List<EntityC_B1MJT> cs1 = q.getResultList();
assertEquals(2, cs1.size());
em.clear();
//find //find
long id = b1.getId(); long id = b1.getId();
Bi_1ToM_JT b2 = em.find(Bi_1ToM_JT.class, id); Bi_1ToM_JT b2 = em.find(Bi_1ToM_JT.class, id);