org.hibernate.persister.entity.UnionSubclassEntityPersister Maven / Gradle / Ivy
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.persister.entity;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cfg.Settings;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IdentityGenerator;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.StaticFilterAliasGenerator;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.internal.util.collections.SingletonIterator;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.sql.SelectFragment;
import org.hibernate.sql.SimpleSelect;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
/**
* Implementation of the "table-per-concrete-class" or "roll-down" mapping
* strategy for an entity and its inheritence hierarchy.
*
* @author Gavin King
*/
public class UnionSubclassEntityPersister extends AbstractEntityPersister {
// the class hierarchy structure
private final String subquery;
private final String tableName;
//private final String rootTableName;
private final String[] subclassClosure;
private final String[] spaces;
private final String[] subclassSpaces;
private final Object discriminatorValue;
private final String discriminatorSQLValue;
private final Map subclassByDiscriminatorValue = new HashMap();
private final String[] constraintOrderedTableNames;
private final String[][] constraintOrderedKeyColumnNames;
//INITIALIZATION:
public UnionSubclassEntityPersister(
final PersistentClass persistentClass,
final EntityRegionAccessStrategy cacheAccessStrategy,
final NaturalIdRegionAccessStrategy naturalIdRegionAccessStrategy,
final SessionFactoryImplementor factory,
final Mapping mapping) throws HibernateException {
super( persistentClass, cacheAccessStrategy, naturalIdRegionAccessStrategy, factory );
if ( getIdentifierGenerator() instanceof IdentityGenerator ) {
throw new MappingException(
"Cannot use identity column key generation with mapping for: " +
getEntityName()
);
}
// TABLE
tableName = persistentClass.getTable().getQualifiedName(
factory.getDialect(),
factory.getSettings().getDefaultCatalogName(),
factory.getSettings().getDefaultSchemaName()
);
/*rootTableName = persistentClass.getRootTable().getQualifiedName(
factory.getDialect(),
factory.getDefaultCatalog(),
factory.getDefaultSchema()
);*/
//Custom SQL
String sql;
boolean callable = false;
ExecuteUpdateResultCheckStyle checkStyle = null;
sql = persistentClass.getCustomSQLInsert();
callable = sql != null && persistentClass.isCustomInsertCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLInsertCheckStyle();
customSQLInsert = new String[] { sql };
insertCallable = new boolean[] { callable };
insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
sql = persistentClass.getCustomSQLUpdate();
callable = sql != null && persistentClass.isCustomUpdateCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLUpdateCheckStyle();
customSQLUpdate = new String[] { sql };
updateCallable = new boolean[] { callable };
updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
sql = persistentClass.getCustomSQLDelete();
callable = sql != null && persistentClass.isCustomDeleteCallable();
checkStyle = sql == null
? ExecuteUpdateResultCheckStyle.COUNT
: persistentClass.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( sql, callable )
: persistentClass.getCustomSQLDeleteCheckStyle();
customSQLDelete = new String[] { sql };
deleteCallable = new boolean[] { callable };
deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };
discriminatorValue = persistentClass.getSubclassId();
discriminatorSQLValue = String.valueOf( persistentClass.getSubclassId() );
// PROPERTIES
int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName();
// SUBCLASSES
subclassByDiscriminatorValue.put(
persistentClass.getSubclassId(),
persistentClass.getEntityName()
);
if ( persistentClass.isPolymorphic() ) {
Iterator iter = persistentClass.getSubclassIterator();
int k=1;
while ( iter.hasNext() ) {
Subclass sc = (Subclass) iter.next();
subclassClosure[k++] = sc.getEntityName();
subclassByDiscriminatorValue.put( sc.getSubclassId(), sc.getEntityName() );
}
}
//SPACES
//TODO: i'm not sure, but perhaps we should exclude
// abstract denormalized tables?
int spacesSize = 1 + persistentClass.getSynchronizedTables().size();
spaces = new String[spacesSize];
spaces[0] = tableName;
Iterator iter = persistentClass.getSynchronizedTables().iterator();
for ( int i=1; i 2 ) {
//chop the last union (all)
buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) );
}
return buf.append(" )").toString();
}
protected String[] getSubclassTableKeyColumns(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return getIdentifierColumnNames();
}
public String getSubclassTableName(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return tableName;
}
public int getSubclassTableSpan() {
return 1;
}
protected boolean isClassOrSuperclassTable(int j) {
if (j!=0) throw new AssertionFailure("only one table");
return true;
}
public String getPropertyTableName(String propertyName) {
//TODO: check this....
return getTableName();
}
public String[] getConstraintOrderedTableNameClosure() {
return constraintOrderedTableNames;
}
public String[][] getContraintOrderedTableKeyColumnClosure() {
return constraintOrderedKeyColumnNames;
}
@Override
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
return new StaticFilterAliasGenerator(rootAlias);
}
}