mirror of https://github.com/apache/openjpa.git
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:
parent
01c26a9e21
commit
6f1b9627fe
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue