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