Base class for strategies that are stored as a collection, even if
their field value is something else. Handles data loading and basic query
functionality. Subclasses must implement abstract methods and
insert/update/delete behavior as well as overriding
if necessary.
| Method from org.apache.openjpa.jdbc.meta.strats.StoreCollectionFieldStrategy Detail: |
protected void add(JDBCStore store,
Object coll,
Object obj) {
((Collection) coll).add(obj);
}
Add an item to the data structure representing a field value.
By default, assumes the structure is a collection. |
protected ForeignKey getJoinForeignKey() {
return getJoinForeignKey(getDefaultElementMapping(false));
}
|
abstract protected ForeignKey getJoinForeignKey(ClassMapping elem)
|
public boolean isEagerSelectToMany() {
return true;
}
|
abstract protected Joins join(Joins joins,
ClassMapping elem)
|
abstract protected Joins joinElementRelation(Joins joins,
ClassMapping elem)
|
public void load(OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch) throws SQLException {
if (field.isLRS()) {
Proxy coll = newLRSProxy();
// if this is ordered we need to know the next seq to use in case
// objects are added to the collection
if (field.getOrderColumn() != null) {
// we don't allow ordering table per class one-many's, so
// we know we don't need a union
Select sel = store.getSQLFactory().newSelect();
sel.setAggregate(true);
StringBuffer sql = new StringBuffer();
sql.append("MAX(").
append(sel.getColumnAlias(field.getOrderColumn())).
append(")");
sel.select(sql.toString(), field);
ClassMapping rel = getDefaultElementMapping(false);
sel.whereForeignKey(getJoinForeignKey(rel),
sm.getObjectId(), field.getDefiningMapping(), store);
Result res = sel.execute(store, fetch);
try {
res.next();
coll.getChangeTracker().setNextSequence
(res.getInt(field) + 1);
} finally {
res.close();
}
}
sm.storeObjectField(field.getIndex(), coll);
return;
}
// select data for this sm
final ClassMapping[] elems = getIndependentElementMappings(true);
final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
Union union = store.getSQLFactory().newUnion
(Math.max(1, elems.length));
union.select(new Union.Selector() {
public void select(Select sel, int idx) {
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
resJoins[idx] = selectAll(sel, elem, sm, store, fetch,
JDBCFetchConfiguration.EAGER_PARALLEL);
}
});
// create proxy
Object coll;
ChangeTracker ct = null;
if (field.getTypeCode() == JavaTypes.ARRAY)
coll = new ArrayList();
else {
coll = sm.newProxy(field.getIndex());
if (coll instanceof Proxy)
ct = ((Proxy) coll).getChangeTracker();
}
// load values
Result res = union.execute(store, fetch);
try {
int seq = -1;
while (res.next()) {
if (ct != null && field.getOrderColumn() != null)
seq = res.getInt(field.getOrderColumn());
add(store, coll, loadElement(sm, store, fetch, res,
resJoins[res.indexOf()]));
}
if (ct != null && field.getOrderColumn() != null)
ct.setNextSequence(seq + 1);
} finally {
res.close();
}
// set into sm
if (field.getTypeCode() == JavaTypes.ARRAY)
sm.storeObject(field.getIndex(), JavaTypes.toArray
((Collection) coll, field.getElement().getType()));
else
sm.storeObject(field.getIndex(), coll);
}
|
public void loadEagerJoin(OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
Result res) throws SQLException {
// initialize field value
Object coll;
if (field.getTypeCode() == JavaTypes.ARRAY)
coll = new ArrayList();
else
coll = sm.newProxy(field.getIndex());
Joins dataJoins = null;
Joins refJoins = res.newJoins().setVariable("*");
join(refJoins, false);
ClassMapping ownerMapping = field.getDefiningMapping();
Object ref = null;
int seq = 0;
int typeIdx = res.indexOf();
for (int i = 0; true; i++) {
// extract the owner id value
ref = getNextRef(ownerMapping, store, res, ref, refJoins);
if (ref == null) {
// if the old coll was an ordered tracking proxy, set
// its seq value to the last order val we read
if (seq != 0 && coll instanceof Proxy)
((Proxy) coll).getChangeTracker().setNextSequence(seq);
if (i != 0)
res.pushBack();
break;
}
// do same joins as for load
if (dataJoins == null) {
dataJoins = res.newJoins().setVariable("*");
dataJoins = join(dataJoins, false);
dataJoins = joinRelation(dataJoins, false, false);
}
if (field.getOrderColumn() != null)
seq = res.getInt(field.getOrderColumn(), refJoins) + 1;
res.setBaseMapping(null);
add(store, coll, loadElement(sm, store, fetch, res, dataJoins));
if (!res.next() || res.indexOf() != typeIdx) {
res.pushBack();
break;
}
}
// load the collection into the object
if (field.getTypeCode() == JavaTypes.ARRAY)
sm.storeObject(field.getIndex(), JavaTypes.toArray
((Collection) coll, field.getElement().getType()));
else
sm.storeObject(field.getIndex(), coll);
}
|
public Object loadEagerParallel(OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
Object res) throws SQLException {
// process batched results if we haven't already
Map rels;
if (res instanceof Result)
rels = processEagerParallelResult(sm, store, fetch, (Result) res);
else
rels = (Map) res;
// look up the collection for this oid, and store in instance
Object coll = rels.remove(sm.getObjectId());
if (field.getTypeCode() == JavaTypes.ARRAY)
sm.storeObject(field.getIndex(), JavaTypes.toArray
((Collection) coll, field.getElement().getType()));
else {
if (coll == null)
coll = sm.newProxy(field.getIndex());
sm.storeObject(field.getIndex(), coll);
}
return rels;
}
|
abstract protected Object loadElement(OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
Result res,
Joins joins) throws SQLException
Load an element of the collection. The given state manager might be
null if the load is for a projection or for processing eager parallel
results. |
public Object loadProjection(JDBCStore store,
JDBCFetchConfiguration fetch,
Result res,
Joins joins) throws SQLException {
return loadElement(null, store, fetch, res, joins);
}
|
abstract protected Proxy newLRSProxy()
Return a large result set proxy for this field. |
protected Joins selectAll(Select sel,
ClassMapping elem,
OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
int eagerMode) {
sel.whereForeignKey(getJoinForeignKey(elem), sm.getObjectId(),
field.getDefiningMapping(), store);
// order first, then select so that if the projection introduces
// additional ordering, it will be after our required ordering
field.orderLocal(sel, elem, null);
Joins joins = joinElementRelation(sel.newJoins(), elem);
field.orderRelation(sel, elem, joins);
selectElement(sel, elem, store, fetch, eagerMode, joins);
return joins;
}
Select data for loading, starting in field table. |
public void selectEagerJoin(Select sel,
OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
int eagerMode) {
// we limit further eager fetches to joins, because after this point
// the select has been modified such that parallel clones may produce
// invalid sql
boolean outer = field.getNullValue() != FieldMapping.NULL_EXCEPTION;
// force inner join for inner join fetch
if (fetch.hasFetchInnerJoin(field.getFullName(false)))
outer = false;
selectEager(sel, getDefaultElementMapping(true), sm, store, fetch,
JDBCFetchConfiguration.EAGER_JOIN, false,
outer);
}
|
public void selectEagerParallel(SelectExecutor sel,
OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch,
int eagerMode) {
if (!(sel instanceof Union))
selectEager((Select) sel, getDefaultElementMapping(true), sm,
store, fetch, eagerMode, true, false);
else {
final ClassMapping[] elems = getIndependentElementMappings(true);
Union union = (Union) sel;
if (fetch.getSubclassFetchMode(field.getElementMapping().
getTypeMapping()) != fetch.EAGER_JOIN)
union.abortUnion();
union.select(new Union.Selector() {
public void select(Select sel, int idx) {
selectEager(sel, elems[idx], sm, store, fetch, eagerMode,
true, false);
}
});
}
}
|
abstract protected void selectElement(Select sel,
ClassMapping elem,
JDBCStore store,
JDBCFetchConfiguration fetch,
int eagerMode,
Joins joins)
|
public int supportsSelect(Select sel,
int type,
OpenJPAStateManager sm,
JDBCStore store,
JDBCFetchConfiguration fetch) {
if (field.isLRS())
return 0;
if (type == Select.EAGER_PARALLEL)
return Math.max(1, getIndependentElementMappings(true).length);
if (type != Select.EAGER_INNER && type != Select.EAGER_OUTER)
return 0;
if (getIndependentElementMappings(true).length > 1)
return 0;
return (type == Select.EAGER_INNER || store.getDBDictionary().
canOuterJoin(sel.getJoinSyntax(), getJoinForeignKey
(getDefaultElementMapping(false)))) ? 1 : 0;
}
|
protected Collection toCollection(Object val) {
if (field.getTypeCode() == JavaTypes.COLLECTION)
return (Collection) val;
return JavaTypes.toList(val, field.getElement().getType(), false);
}
Convert the field value to a collection. Handles collections and
arrays by default. |