in openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java [1084:1243]
protected ForeignKey createForeignKey(MetaDataContext context,
String prefix, List<Column> given, ForeignKeyDefaults def, Table table,
ClassMapping cls, ClassMapping rel, boolean inversable, boolean adapt) {
assertTable(context, table);
if (prefix == null)
prefix = "generic";
// collect the foreign key columns and their targets
Object[][] joins = createJoins(context, prefix, table, cls, rel,
given, def, inversable, adapt);
_join = JOIN_FORWARD;
// establish local table using any join between two columns; if we only
// find constant joins, then keep default local table (directionless)
Table local = table;
Table foreign = rel.getTable();
Table tmp;
boolean constant = false;
boolean localSet = false;
for (Object[] objects : joins) {
if (objects[1] instanceof Column) {
tmp = ((Column) objects[0]).getTable();
if (!localSet) {
local = tmp;
localSet = true;
}
else if (tmp != local)
throw new MetaDataException(_loc.get(prefix
+ "-mult-fk-tables", context, local, tmp));
foreign = ((Column) objects[1]).getTable();
if (objects[2] == Boolean.TRUE)
_join = JOIN_INVERSE;
}
else
constant = true;
}
// if this is not a constant join, look for existing foreign key
// on local columns
ForeignKey exist = null;
if (!constant && local.getForeignKeys().length > 0) {
Column[] cols = new Column[joins.length];
Column[] pks = new Column[joins.length];
for (int i = 0; i < joins.length; i++) {
cols[i] = (Column) joins[i][0];
pks[i] = (Column) joins[i][1];
}
ForeignKey[] fks = local.getForeignKeys();
for (ForeignKey fk : fks) {
if (fk.getConstantColumns().length == 0
&& fk.getConstantPrimaryKeyColumns().length == 0
&& fk.columnsMatch(cols, pks)) {
exist = fk;
break;
}
}
}
MappingRepository repos = (MappingRepository) context.getRepository();
DBDictionary dict = repos.getDBDictionary();
if (exist != null) {
// make existing key logical?
if (!_canFK) {
if (exist.getDeleteAction() != ForeignKey.ACTION_NONE && !adapt)
throw new MetaDataException(_loc.get(prefix
+ "-fk-exists", context));
exist.setDeleteAction(ForeignKey.ACTION_NONE);
}
if (_fk != null && _fk.isDeferred() && !exist.isDeferred()) {
Log log = repos.getLog();
if (log.isWarnEnabled())
log.warn(_loc.get(prefix + "-defer-fk", context));
}
// allow user-given info to override existing key if we're adapting;
// template info cannot override existing key
if (adapt && _fk != null) {
if (_fk.getUpdateAction() != ForeignKey.ACTION_NONE)
exist.setUpdateAction(_fk.getUpdateAction());
if (_fk.getDeleteAction() != ForeignKey.ACTION_NONE)
exist.setDeleteAction(_fk.getDeleteAction());
}
setIOFromJoins(exist, joins);
return exist;
}
DBIdentifier name = DBIdentifier.NULL;
int delAction = ForeignKey.ACTION_NONE;
int upAction = ForeignKey.ACTION_NONE;
boolean deferred = false;
boolean fill = repos.getMappingDefaults().defaultMissingInfo();
ForeignKey tmplate = (def == null) ? null
: def.get(local, foreign, _join == JOIN_INVERSE);
if (_fk != null && (tmplate == null || (!adapt && !fill))) {
// if not adapting or no template info use given data
name = _fk.getIdentifier();
delAction = _fk.getDeleteAction();
upAction = _fk.getUpdateAction();
deferred = _fk.isDeferred();
} else if (_canFK && (adapt || fill)) {
if (_fk == null && tmplate != null) {
// no user given info; use template data
name = tmplate.getIdentifier();
delAction = tmplate.getDeleteAction();
upAction = tmplate.getUpdateAction();
deferred = tmplate.isDeferred();
} else if (_fk != null && tmplate != null) {
// merge user and template data, always letting user info win
name = _fk.getIdentifier();
if (DBIdentifier.isNull(name) && !DBIdentifier.isNull(tmplate.getIdentifier()))
name = tmplate.getIdentifier();
delAction = _fk.getDeleteAction();
if (delAction == ForeignKey.ACTION_NONE)
delAction = tmplate.getDeleteAction();
upAction = _fk.getUpdateAction();
if (upAction == ForeignKey.ACTION_NONE)
upAction = tmplate.getUpdateAction();
deferred = _fk.isDeferred();
}
}
if (!dict.supportsDeleteAction(delAction)
|| !dict.supportsUpdateAction(upAction)) {
Log log = repos.getLog();
if (log.isWarnEnabled())
log.warn(_loc.get(prefix + "-unsupported-fk-action", context));
delAction = ForeignKey.ACTION_NONE;
upAction = ForeignKey.ACTION_NONE;
}
if (deferred && !dict.supportsDeferredConstraints) {
Log log = repos.getLog();
if (log.isWarnEnabled())
log.warn(_loc.get(prefix + "-create-defer-fk",
context, dict.platform));
deferred = false;
}
// create foreign key with merged info
ForeignKey fk = local.addForeignKey(name);
fk.setDeleteAction(delAction);
fk.setUpdateAction(upAction);
fk.setDeferred(deferred);
// add joins to key
Column col;
for (Object[] join : joins) {
col = (Column) join[0];
if (join[1] instanceof Column)
fk.join(col, (Column) join[1]);
else if ((join[2] == Boolean.TRUE) != (_join == JOIN_INVERSE))
fk.joinConstant(join[1], col);
else
fk.joinConstant(col, join[1]);
}
setIOFromJoins(fk, joins);
return fk;
}