HHH-4250 : @ManyToOne - @OneToMany doesn't work with @Inheritance(strategy= InheritanceType.JOINED)
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19894 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
bf9ef75d06
commit
f9f2031241
|
@ -41,6 +41,7 @@ import org.hibernate.engine.Mapping;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.Versioning;
|
import org.hibernate.engine.Versioning;
|
||||||
import org.hibernate.mapping.Column;
|
import org.hibernate.mapping.Column;
|
||||||
|
import org.hibernate.mapping.Join;
|
||||||
import org.hibernate.mapping.KeyValue;
|
import org.hibernate.mapping.KeyValue;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -94,6 +95,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
private final int[] subclassColumnTableNumberClosure;
|
private final int[] subclassColumnTableNumberClosure;
|
||||||
private final int[] subclassFormulaTableNumberClosure;
|
private final int[] subclassFormulaTableNumberClosure;
|
||||||
|
|
||||||
|
private final boolean[] subclassTableSequentialSelect;
|
||||||
|
private final boolean[] subclassTableIsLazyClosure;
|
||||||
|
|
||||||
// subclass discrimination works by assigning particular
|
// subclass discrimination works by assigning particular
|
||||||
// values to certain combinations of null primary key
|
// values to certain combinations of null primary key
|
||||||
// values in the outer join using an SQL CASE
|
// values in the outer join using an SQL CASE
|
||||||
|
@ -173,6 +177,44 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
keyColumnReaderTemplates.add(keyColReaderTemplates);
|
keyColumnReaderTemplates.add(keyColReaderTemplates);
|
||||||
cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
|
cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Span of the tables directly mapped by this entity and super-classes, if any
|
||||||
|
int coreTableSpan = tables.size();
|
||||||
|
|
||||||
|
Iterator joinIter = persistentClass.getJoinClosureIterator();
|
||||||
|
while ( joinIter.hasNext() ) {
|
||||||
|
Join join = (Join) joinIter.next();
|
||||||
|
|
||||||
|
Table tab = join.getTable();
|
||||||
|
|
||||||
|
String tabname = tab.getQualifiedName(
|
||||||
|
factory.getDialect(),
|
||||||
|
factory.getSettings().getDefaultCatalogName(),
|
||||||
|
factory.getSettings().getDefaultSchemaName()
|
||||||
|
);
|
||||||
|
tables.add(tabname);
|
||||||
|
|
||||||
|
KeyValue key = join.getKey();
|
||||||
|
int joinIdColumnSpan = key.getColumnSpan();
|
||||||
|
|
||||||
|
String[] keyCols = new String[joinIdColumnSpan];
|
||||||
|
String[] keyColReaders = new String[joinIdColumnSpan];
|
||||||
|
String[] keyColReaderTemplates = new String[joinIdColumnSpan];
|
||||||
|
|
||||||
|
Iterator citer = key.getColumnIterator();
|
||||||
|
|
||||||
|
for ( int k=0; k<joinIdColumnSpan; k++ ) {
|
||||||
|
Column column = (Column) citer.next();
|
||||||
|
keyCols[k] = column.getQuotedName( factory.getDialect() );
|
||||||
|
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
|
||||||
|
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||||
|
}
|
||||||
|
keyColumns.add(keyCols);
|
||||||
|
keyColumnReaders.add(keyColReaders);
|
||||||
|
keyColumnReaderTemplates.add(keyColReaderTemplates);
|
||||||
|
cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
|
||||||
|
}
|
||||||
|
|
||||||
naturalOrderTableNames = ArrayHelper.toStringArray(tables);
|
naturalOrderTableNames = ArrayHelper.toStringArray(tables);
|
||||||
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
|
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
|
||||||
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
|
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
|
||||||
|
@ -181,11 +223,16 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
|
|
||||||
ArrayList subtables = new ArrayList();
|
ArrayList subtables = new ArrayList();
|
||||||
ArrayList isConcretes = new ArrayList();
|
ArrayList isConcretes = new ArrayList();
|
||||||
|
ArrayList isDeferreds = new ArrayList();
|
||||||
|
ArrayList isLazies = new ArrayList();
|
||||||
|
|
||||||
keyColumns = new ArrayList();
|
keyColumns = new ArrayList();
|
||||||
titer = persistentClass.getSubclassTableClosureIterator();
|
titer = persistentClass.getSubclassTableClosureIterator();
|
||||||
while ( titer.hasNext() ) {
|
while ( titer.hasNext() ) {
|
||||||
Table tab = (Table) titer.next();
|
Table tab = (Table) titer.next();
|
||||||
isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
|
isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
|
||||||
|
isDeferreds.add(Boolean.FALSE);
|
||||||
|
isLazies.add(Boolean.FALSE);
|
||||||
String tabname = tab.getQualifiedName(
|
String tabname = tab.getQualifiedName(
|
||||||
factory.getDialect(),
|
factory.getDialect(),
|
||||||
factory.getSettings().getDefaultCatalogName(),
|
factory.getSettings().getDefaultCatalogName(),
|
||||||
|
@ -199,25 +246,64 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
}
|
}
|
||||||
keyColumns.add(key);
|
keyColumns.add(key);
|
||||||
}
|
}
|
||||||
subclassTableNameClosure = ArrayHelper.toStringArray(subtables);
|
|
||||||
subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
|
|
||||||
isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
|
|
||||||
|
|
||||||
constraintOrderedTableNames = new String[subclassTableNameClosure.length];
|
//Add joins
|
||||||
constraintOrderedKeyColumnNames = new String[subclassTableNameClosure.length][];
|
joinIter = persistentClass.getSubclassJoinClosureIterator();
|
||||||
int currentPosition = 0;
|
while ( joinIter.hasNext() ) {
|
||||||
for ( int i = subclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
|
Join join = (Join) joinIter.next();
|
||||||
constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
|
|
||||||
constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
|
Table tab = join.getTable();
|
||||||
|
|
||||||
|
isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassTable(tab) ) );
|
||||||
|
isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
|
||||||
|
isLazies.add(new Boolean(join.isLazy()));
|
||||||
|
|
||||||
|
String tabname = tab.getQualifiedName(
|
||||||
|
factory.getDialect(),
|
||||||
|
factory.getSettings().getDefaultCatalogName(),
|
||||||
|
factory.getSettings().getDefaultSchemaName()
|
||||||
|
);
|
||||||
|
subtables.add(tabname);
|
||||||
|
String[] key = new String[idColumnSpan];
|
||||||
|
Iterator citer = tab.getPrimaryKey().getColumnIterator();
|
||||||
|
for ( int k=0; k<idColumnSpan; k++ ) {
|
||||||
|
key[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
|
||||||
|
}
|
||||||
|
keyColumns.add(key);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String [] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray(subtables);
|
||||||
|
String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(keyColumns);
|
||||||
|
isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
|
||||||
|
subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
|
||||||
|
subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
|
||||||
|
|
||||||
|
constraintOrderedTableNames = new String[naturalOrderSubclassTableNameClosure.length];
|
||||||
|
constraintOrderedKeyColumnNames = new String[naturalOrderSubclassTableNameClosure.length][];
|
||||||
|
int currentPosition = 0;
|
||||||
|
for ( int i = naturalOrderSubclassTableNameClosure.length - 1; i >= 0 ; i--, currentPosition++ ) {
|
||||||
|
constraintOrderedTableNames[currentPosition] = naturalOrderSubclassTableNameClosure[i];
|
||||||
|
constraintOrderedKeyColumnNames[currentPosition] = naturalOrderSubclassTableKeyColumnClosure[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suppose an entity Client extends Person, mapped to the tables CLIENT and PERSON respectively.
|
||||||
|
* For the Client entity:
|
||||||
|
* naturalOrderTableNames -> PERSON, CLIENT; this reflects the sequence in which the tables are
|
||||||
|
* added to the meta-data when the annotated entities are processed.
|
||||||
|
* However, in some instances, for example when generating joins, the CLIENT table needs to be
|
||||||
|
* the first table as it will the driving table.
|
||||||
|
* tableNames -> CLIENT, PERSON
|
||||||
|
*/
|
||||||
|
|
||||||
tableSpan = naturalOrderTableNames.length;
|
tableSpan = naturalOrderTableNames.length;
|
||||||
tableNames = reverse(naturalOrderTableNames);
|
tableNames = reverse(naturalOrderTableNames, coreTableSpan);
|
||||||
tableKeyColumns = reverse(naturalOrderTableKeyColumns);
|
tableKeyColumns = reverse(naturalOrderTableKeyColumns, coreTableSpan);
|
||||||
tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders);
|
tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders, coreTableSpan);
|
||||||
tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates);
|
tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates, coreTableSpan);
|
||||||
reverse(subclassTableNameClosure, tableSpan);
|
subclassTableNameClosure = reverse(naturalOrderSubclassTableNameClosure, coreTableSpan);
|
||||||
reverse(subclassTableKeyColumnClosure, tableSpan);
|
subclassTableKeyColumnClosure = reverse(naturalOrderSubclassTableKeyColumnClosure, coreTableSpan);
|
||||||
|
|
||||||
spaces = ArrayHelper.join(
|
spaces = ArrayHelper.join(
|
||||||
tableNames,
|
tableNames,
|
||||||
|
@ -236,7 +322,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
|
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
|
||||||
|
|
||||||
PersistentClass pc = persistentClass;
|
PersistentClass pc = persistentClass;
|
||||||
int jk = tableSpan-1;
|
int jk = coreTableSpan-1;
|
||||||
while (pc!=null) {
|
while (pc!=null) {
|
||||||
customSQLInsert[jk] = pc.getCustomSQLInsert();
|
customSQLInsert[jk] = pc.getCustomSQLInsert();
|
||||||
insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
|
insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
|
||||||
|
@ -256,12 +342,35 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
jk--;
|
jk--;
|
||||||
pc = pc.getSuperclass();
|
pc = pc.getSuperclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( jk != -1 ) {
|
if ( jk != -1 ) {
|
||||||
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
|
throw new AssertionFailure( "Tablespan does not match height of joined-subclass hiearchy." );
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROPERTIES
|
joinIter = persistentClass.getJoinClosureIterator();
|
||||||
|
int j = coreTableSpan;
|
||||||
|
while ( joinIter.hasNext() ) {
|
||||||
|
Join join = (Join) joinIter.next();
|
||||||
|
|
||||||
|
customSQLInsert[j] = join.getCustomSQLInsert();
|
||||||
|
insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
|
||||||
|
insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
|
||||||
|
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
|
||||||
|
: join.getCustomSQLInsertCheckStyle();
|
||||||
|
customSQLUpdate[j] = join.getCustomSQLUpdate();
|
||||||
|
updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
|
||||||
|
updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
|
||||||
|
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
|
||||||
|
: join.getCustomSQLUpdateCheckStyle();
|
||||||
|
customSQLDelete[j] = join.getCustomSQLDelete();
|
||||||
|
deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
|
||||||
|
deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
|
||||||
|
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
|
||||||
|
: join.getCustomSQLDeleteCheckStyle();
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PROPERTIES
|
||||||
int hydrateSpan = getPropertySpan();
|
int hydrateSpan = getPropertySpan();
|
||||||
naturalOrderPropertyTableNumbers = new int[hydrateSpan];
|
naturalOrderPropertyTableNumbers = new int[hydrateSpan];
|
||||||
propertyTableNumbers = new int[hydrateSpan];
|
propertyTableNumbers = new int[hydrateSpan];
|
||||||
|
@ -297,7 +406,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
factory.getSettings().getDefaultSchemaName()
|
factory.getSettings().getDefaultSchemaName()
|
||||||
);
|
);
|
||||||
Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
|
Integer tabnum = new Integer( getTableId(tabname, subclassTableNameClosure) );
|
||||||
propTableNumbers.add(tabnum);
|
propTableNumbers.add(tabnum);
|
||||||
|
|
||||||
Iterator citer = prop.getColumnIterator();
|
Iterator citer = prop.getColumnIterator();
|
||||||
while ( citer.hasNext() ) {
|
while ( citer.hasNext() ) {
|
||||||
|
@ -383,6 +492,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isSubclassTableSequentialSelect(int j) {
|
||||||
|
return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*public void postInstantiate() throws MappingException {
|
/*public void postInstantiate() throws MappingException {
|
||||||
super.postInstantiate();
|
super.postInstantiate();
|
||||||
//TODO: other lock modes?
|
//TODO: other lock modes?
|
||||||
|
@ -463,24 +577,51 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] reverse(String[] objects) {
|
|
||||||
int len = objects.length;
|
/**
|
||||||
String[] temp = new String[len];
|
* Reverse the first n elements of the incoming array
|
||||||
for (int i=0; i<len; i++) {
|
* @param objects
|
||||||
temp[i] = objects[len-i-1];
|
* @param n
|
||||||
|
* @return New array with the first n elements in reversed order
|
||||||
|
*/
|
||||||
|
private static final String[] reverse(String [] objects, int n) {
|
||||||
|
|
||||||
|
int size = objects.length;
|
||||||
|
String[] temp = new String[size];
|
||||||
|
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
temp[i] = objects[n-i-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=n; i < size; i++) {
|
||||||
|
temp[i] = objects[i];
|
||||||
|
}
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[][] reverse(String[][] objects) {
|
/**
|
||||||
int len = objects.length;
|
* Reverse the first n elements of the incoming array
|
||||||
String[][] temp = new String[len][];
|
* @param objects
|
||||||
for (int i=0; i<len; i++) {
|
* @param n
|
||||||
temp[i] = objects[len-i-1];
|
* @return New array with the first n elements in reversed order
|
||||||
|
*/
|
||||||
|
private static final String[][] reverse(String[][] objects, int n) {
|
||||||
|
int size = objects.length;
|
||||||
|
String[][] temp = new String[size][];
|
||||||
|
for (int i=0; i<n; i++) {
|
||||||
|
temp[i] = objects[n-i-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i=n; i<size; i++) {
|
||||||
|
temp[i] = objects[i];
|
||||||
|
}
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public String fromTableFragment(String alias) {
|
public String fromTableFragment(String alias) {
|
||||||
return getTableName() + ' ' + alias;
|
return getTableName() + ' ' + alias;
|
||||||
}
|
}
|
||||||
|
@ -597,6 +738,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
return subclassTableNameClosure.length;
|
return subclassTableNameClosure.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isSubclassTableLazy(int j) {
|
||||||
|
return subclassTableIsLazyClosure[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected boolean isClassOrSuperclassTable(int j) {
|
protected boolean isClassOrSuperclassTable(int j) {
|
||||||
return isClassOrSuperclassTable[j];
|
return isClassOrSuperclassTable[j];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue