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.kernel.*;
|
||||
import org.apache.openjpa.util.*;
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.jdbc.meta.*;
|
||||
import org.apache.openjpa.jdbc.kernel.*;
|
||||
import org.apache.openjpa.jdbc.schema.*;
|
||||
|
@ -88,9 +89,7 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
sel.whereForeignKey(field.getJoinForeignKey(),
|
||||
sm.getObjectId(), field.getDefiningMapping(), store);
|
||||
FieldMapping mapped = field.getMappedByMapping();
|
||||
Joins joins = null;
|
||||
if (mapped == null)
|
||||
joins = joinValueRelation(sel.newJoins(), vals[idx]);
|
||||
Joins joins = joinValueRelation(sel.newJoins(), vals[idx]);
|
||||
|
||||
sel.select(vals[idx], field.getElementMapping().
|
||||
getSelectSubclasses(), store, fetch, eagerMode, joins);
|
||||
|
@ -123,7 +122,10 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
|
||||
public Joins joinValueRelation(Joins joins, ClassMapping val) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -195,10 +197,26 @@ public class HandlerRelationMapTableFieldStrategy
|
|||
valsm = RelationStrategies.getStateManager(entry.getValue(),
|
||||
ctx);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
throws SQLException {
|
||||
if (field.getMappedBy() != null)
|
||||
|
|
|
@ -19,21 +19,26 @@
|
|||
package org.apache.openjpa.jdbc.meta.strats;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
|
||||
import org.apache.openjpa.jdbc.kernel.JDBCStore;
|
||||
import org.apache.openjpa.jdbc.meta.ClassMapping;
|
||||
import org.apache.openjpa.jdbc.meta.FieldMapping;
|
||||
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.schema.ForeignKey;
|
||||
import org.apache.openjpa.jdbc.sql.Joins;
|
||||
import org.apache.openjpa.jdbc.sql.Result;
|
||||
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.Select;
|
||||
import org.apache.openjpa.kernel.OpenJPAStateManager;
|
||||
import org.apache.openjpa.kernel.StoreContext;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.JavaTypes;
|
||||
|
@ -213,8 +218,8 @@ public abstract class MapTableFieldStrategy
|
|||
log.info(_loc.get("coll-owner", field, mapped));
|
||||
ValueMapping elem = mapped.getElementMapping();
|
||||
ForeignKey fk = elem.getForeignKey();
|
||||
field.setForeignKey(fk);
|
||||
field.setJoinForeignKey(fk);
|
||||
field.getElementMapping().setForeignKey(mapped.getJoinForeignKey());
|
||||
} else
|
||||
throw new MetaDataException(_loc.get("not-inv-relation",
|
||||
field, mapped));
|
||||
|
@ -249,4 +254,51 @@ public abstract class MapTableFieldStrategy
|
|||
return false;
|
||||
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.kernel.*;
|
||||
import org.apache.openjpa.util.*;
|
||||
import org.apache.openjpa.enhance.PersistenceCapable;
|
||||
import org.apache.openjpa.jdbc.meta.*;
|
||||
import org.apache.openjpa.jdbc.kernel.*;
|
||||
import org.apache.openjpa.jdbc.schema.*;
|
||||
|
@ -111,9 +112,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
// order before select in case we're faking union with
|
||||
// multiple selects; order vals used to merge results
|
||||
FieldMapping mapped = field.getMappedByMapping();
|
||||
Joins joins = null;
|
||||
if (mapped == null)
|
||||
joins = joinValueRelation(sel.newJoins(), vals[idx]);
|
||||
Joins joins = joinValueRelation(sel.newJoins(), vals[idx]);
|
||||
sel.orderBy(field.getKeyMapping().getColumns(), true, true);
|
||||
sel.select(vals[idx], field.getElementMapping().
|
||||
getSelectSubclasses(), store, fetch, eagerMode, joins);
|
||||
|
@ -166,7 +165,10 @@ public class RelationRelationMapTableFieldStrategy
|
|||
|
||||
public Joins joinValueRelation(Joins joins, ClassMapping val) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -180,13 +182,17 @@ public class RelationRelationMapTableFieldStrategy
|
|||
if (val.getTypeCode() != JavaTypes.PC || val.isEmbeddedPC())
|
||||
throw new MetaDataException(_loc.get("not-relation", val));
|
||||
FieldMapping mapped = field.getMappedByMapping();
|
||||
if (mapped != null)
|
||||
DBDictionary dict = field.getMappingRepository().getDBDictionary();
|
||||
String keyName = null;
|
||||
if (mapped != null) {
|
||||
handleMappedBy(adapt);
|
||||
else {
|
||||
keyName = dict.getValidColumnName("vkey", field.getTable());
|
||||
} else {
|
||||
field.mapJoin(adapt, true);
|
||||
mapTypeJoin(val, "value", adapt);
|
||||
keyName = dict.getValidColumnName("key", field.getTable());
|
||||
}
|
||||
mapTypeJoin(key, "key", adapt);
|
||||
mapTypeJoin(key, keyName, adapt);
|
||||
|
||||
field.mapPrimaryKey(adapt);
|
||||
}
|
||||
|
@ -211,10 +217,11 @@ public class RelationRelationMapTableFieldStrategy
|
|||
|
||||
public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
|
||||
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 {
|
||||
if (map == null || map.isEmpty())
|
||||
return;
|
||||
|
@ -237,6 +244,15 @@ public class RelationRelationMapTableFieldStrategy
|
|||
valsm = RelationStrategies.getStateManager(entry.getValue(), ctx);
|
||||
key.setForeignKey(row, keysm);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +273,7 @@ public class RelationRelationMapTableFieldStrategy
|
|||
// if no fine-grained change tracking then just delete and reinsert
|
||||
if (ct == null || !ct.isTracking()) {
|
||||
delete(sm, store, rm);
|
||||
insert(sm, rm, map);
|
||||
insert(sm, rm, map, store);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue