OPENJPA-851: ManyToMany Map support

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@736245 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Fay Wang 2009-01-21 06:50:16 +00:00
parent c848009334
commit c21184bf11
3 changed files with 103 additions and 17 deletions

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.lib.util.*;
import org.apache.openjpa.meta.*; import org.apache.openjpa.meta.*;
import org.apache.openjpa.kernel.*; import org.apache.openjpa.kernel.*;
import org.apache.openjpa.util.*; import org.apache.openjpa.util.*;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.meta.*; import org.apache.openjpa.jdbc.meta.*;
import org.apache.openjpa.jdbc.kernel.*; import org.apache.openjpa.jdbc.kernel.*;
import org.apache.openjpa.jdbc.schema.*; import org.apache.openjpa.jdbc.schema.*;
@ -88,9 +89,7 @@ public class HandlerRelationMapTableFieldStrategy
sel.whereForeignKey(field.getJoinForeignKey(), sel.whereForeignKey(field.getJoinForeignKey(),
sm.getObjectId(), field.getDefiningMapping(), store); sm.getObjectId(), field.getDefiningMapping(), store);
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
Joins joins = null; Joins joins = joinValueRelation(sel.newJoins(), vals[idx]);
if (mapped == null)
joins = joinValueRelation(sel.newJoins(), vals[idx]);
sel.select(vals[idx], field.getElementMapping(). sel.select(vals[idx], field.getElementMapping().
getSelectSubclasses(), store, fetch, eagerMode, joins); getSelectSubclasses(), store, fetch, eagerMode, joins);
@ -123,7 +122,10 @@ public class HandlerRelationMapTableFieldStrategy
public Joins joinValueRelation(Joins joins, ClassMapping val) { public Joins joinValueRelation(Joins joins, ClassMapping val) {
ValueMapping vm = field.getElementMapping(); ValueMapping vm = field.getElementMapping();
return joins.joinRelation(field.getName(), vm.getForeignKey(val), val, ForeignKey fk = vm.getForeignKey(val);
if (fk == null)
return null;
return joins.joinRelation(field.getName(), fk, val,
vm.getSelectSubclasses(), false, false); vm.getSelectSubclasses(), false, false);
} }
@ -195,10 +197,26 @@ public class HandlerRelationMapTableFieldStrategy
valsm = RelationStrategies.getStateManager(entry.getValue(), valsm = RelationStrategies.getStateManager(entry.getValue(),
ctx); ctx);
val.setForeignKey(row, valsm); val.setForeignKey(row, valsm);
// So far we poplulated the key/value of each
// map element owned by the entity.
// In the case of ToMany, and both sides
// use Map to represent the relation,
// we need to populate the key value of the owner
// from the view point of the owned side
PersistenceCapable obj = sm.getPersistenceCapable();
if (!populateKey(row, valsm, obj, ctx, rm, store))
rm.flushSecondaryRow(row); rm.flushSecondaryRow(row);
} }
} }
public void setKey(Object keyObj, JDBCStore store, Row row)
throws SQLException {
ValueMapping key = field.getKeyMapping();
HandlerStrategies.set(key, keyObj, store, row, _kcols,
_kio, true);
}
public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
if (field.getMappedBy() != null) if (field.getMappedBy() != null)

View File

@ -19,21 +19,26 @@
package org.apache.openjpa.jdbc.meta.strats; package org.apache.openjpa.jdbc.meta.strats;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection;
import java.util.Map; import java.util.Map;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration; import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore; import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ClassMapping; import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.FieldMapping; import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.FieldStrategy; import org.apache.openjpa.jdbc.meta.FieldStrategy;
import org.apache.openjpa.jdbc.meta.Strategy;
import org.apache.openjpa.jdbc.meta.ValueMapping; import org.apache.openjpa.jdbc.meta.ValueMapping;
import org.apache.openjpa.jdbc.schema.ForeignKey; import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.sql.Joins; import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result; import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.Row; import org.apache.openjpa.jdbc.sql.Row;
import org.apache.openjpa.jdbc.sql.RowImpl;
import org.apache.openjpa.jdbc.sql.RowManager; import org.apache.openjpa.jdbc.sql.RowManager;
import org.apache.openjpa.jdbc.sql.Select; import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.JavaTypes;
@ -213,8 +218,8 @@ public abstract class MapTableFieldStrategy
log.info(_loc.get("coll-owner", field, mapped)); log.info(_loc.get("coll-owner", field, mapped));
ValueMapping elem = mapped.getElementMapping(); ValueMapping elem = mapped.getElementMapping();
ForeignKey fk = elem.getForeignKey(); ForeignKey fk = elem.getForeignKey();
field.setForeignKey(fk);
field.setJoinForeignKey(fk); field.setJoinForeignKey(fk);
field.getElementMapping().setForeignKey(mapped.getJoinForeignKey());
} else } else
throw new MetaDataException(_loc.get("not-inv-relation", throw new MetaDataException(_loc.get("not-inv-relation",
field, mapped)); field, mapped));
@ -249,4 +254,51 @@ public abstract class MapTableFieldStrategy
return false; return false;
return true; return true;
} }
protected boolean populateKey(Row row, OpenJPAStateManager valsm, Object obj,
StoreContext ctx, RowManager rm, JDBCStore store) throws SQLException {
ClassMapping meta = (ClassMapping)valsm.getMetaData();
FieldMapping fm = getFieldMapping(meta);
if (fm == null)
return false;
Map mapObj = (Map)valsm.fetchObject(fm.getIndex());
Collection<Map.Entry> entrySets = mapObj.entrySet();
boolean found = false;
for (Map.Entry entry : entrySets) {
if (entry.getValue() == obj) {
Row newRow = (Row) ((RowImpl)row).clone();
Object keyObj = entry.getKey();
Strategy strat = fm.getStrategy();
if (strat instanceof HandlerRelationMapTableFieldStrategy) {
HandlerRelationMapTableFieldStrategy hrStrat =
(HandlerRelationMapTableFieldStrategy) strat;
hrStrat.setKey(keyObj, store, newRow);
} else if (keyObj instanceof PersistenceCapable) {
OpenJPAStateManager keysm =
RelationStrategies.getStateManager(entry.getKey(), ctx);
ValueMapping key = fm.getKeyMapping();
if (keysm != null)
key.setForeignKey(newRow, keysm);
else
key.setForeignKey(newRow, null);
}
rm.flushSecondaryRow(newRow);
found = true;
}
}
if (found)
return true;
return false;
}
private FieldMapping getFieldMapping(ClassMapping meta) {
FieldMapping[] fields = meta.getFieldMappings();
for (int i = 0; i < fields.length; i++) {
ValueMapping val = fields[i].getValueMapping();
if (fields[i].getMappedByMetaData() == field &&
val.getDeclaredTypeCode() == JavaTypes.MAP)
return fields[i];
}
return null;
}
} }

View File

@ -25,6 +25,7 @@ import org.apache.openjpa.lib.util.*;
import org.apache.openjpa.meta.*; import org.apache.openjpa.meta.*;
import org.apache.openjpa.kernel.*; import org.apache.openjpa.kernel.*;
import org.apache.openjpa.util.*; import org.apache.openjpa.util.*;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.meta.*; import org.apache.openjpa.jdbc.meta.*;
import org.apache.openjpa.jdbc.kernel.*; import org.apache.openjpa.jdbc.kernel.*;
import org.apache.openjpa.jdbc.schema.*; import org.apache.openjpa.jdbc.schema.*;
@ -111,9 +112,7 @@ public class RelationRelationMapTableFieldStrategy
// order before select in case we're faking union with // order before select in case we're faking union with
// multiple selects; order vals used to merge results // multiple selects; order vals used to merge results
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
Joins joins = null; Joins joins = joinValueRelation(sel.newJoins(), vals[idx]);
if (mapped == null)
joins = joinValueRelation(sel.newJoins(), vals[idx]);
sel.orderBy(field.getKeyMapping().getColumns(), true, true); sel.orderBy(field.getKeyMapping().getColumns(), true, true);
sel.select(vals[idx], field.getElementMapping(). sel.select(vals[idx], field.getElementMapping().
getSelectSubclasses(), store, fetch, eagerMode, joins); getSelectSubclasses(), store, fetch, eagerMode, joins);
@ -166,7 +165,10 @@ public class RelationRelationMapTableFieldStrategy
public Joins joinValueRelation(Joins joins, ClassMapping val) { public Joins joinValueRelation(Joins joins, ClassMapping val) {
ValueMapping vm = field.getElementMapping(); ValueMapping vm = field.getElementMapping();
return joins.joinRelation(field.getName(), vm.getForeignKey(val), val, ForeignKey fk = vm.getForeignKey(val);
if (fk == null)
return null;
return joins.joinRelation(field.getName(), fk, val,
vm.getSelectSubclasses(), false, false); vm.getSelectSubclasses(), false, false);
} }
@ -180,13 +182,17 @@ public class RelationRelationMapTableFieldStrategy
if (val.getTypeCode() != JavaTypes.PC || val.isEmbeddedPC()) if (val.getTypeCode() != JavaTypes.PC || val.isEmbeddedPC())
throw new MetaDataException(_loc.get("not-relation", val)); throw new MetaDataException(_loc.get("not-relation", val));
FieldMapping mapped = field.getMappedByMapping(); FieldMapping mapped = field.getMappedByMapping();
if (mapped != null) DBDictionary dict = field.getMappingRepository().getDBDictionary();
String keyName = null;
if (mapped != null) {
handleMappedBy(adapt); handleMappedBy(adapt);
else { keyName = dict.getValidColumnName("vkey", field.getTable());
} else {
field.mapJoin(adapt, true); field.mapJoin(adapt, true);
mapTypeJoin(val, "value", adapt); mapTypeJoin(val, "value", adapt);
keyName = dict.getValidColumnName("key", field.getTable());
} }
mapTypeJoin(key, "key", adapt); mapTypeJoin(key, keyName, adapt);
field.mapPrimaryKey(adapt); field.mapPrimaryKey(adapt);
} }
@ -211,10 +217,11 @@ public class RelationRelationMapTableFieldStrategy
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm) public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException { throws SQLException {
insert(sm, rm, (Map) sm.fetchObject(field.getIndex())); insert(sm, rm, (Map) sm.fetchObject(field.getIndex()), store);
} }
private void insert(OpenJPAStateManager sm, RowManager rm, Map map) private void insert(OpenJPAStateManager sm, RowManager rm, Map map,
JDBCStore store)
throws SQLException { throws SQLException {
if (map == null || map.isEmpty()) if (map == null || map.isEmpty())
return; return;
@ -237,6 +244,15 @@ public class RelationRelationMapTableFieldStrategy
valsm = RelationStrategies.getStateManager(entry.getValue(), ctx); valsm = RelationStrategies.getStateManager(entry.getValue(), ctx);
key.setForeignKey(row, keysm); key.setForeignKey(row, keysm);
val.setForeignKey(row, valsm); val.setForeignKey(row, valsm);
// so far, we poplulated the key/value of each
// map element owned by the entity.
// In the case of ToMany, and both sides
// use Map to represent the relation,
// we need to populate the key value of the owner
// from the view point of the owned side
PersistenceCapable obj = sm.getPersistenceCapable();
if (!populateKey(row, valsm, obj, ctx, rm, store))
rm.flushSecondaryRow(row); rm.flushSecondaryRow(row);
} }
} }
@ -257,7 +273,7 @@ public class RelationRelationMapTableFieldStrategy
// if no fine-grained change tracking then just delete and reinsert // if no fine-grained change tracking then just delete and reinsert
if (ct == null || !ct.isTracking()) { if (ct == null || !ct.isTracking()) {
delete(sm, store, rm); delete(sm, store, rm);
insert(sm, rm, map); insert(sm, rm, map, store);
return; return;
} }