HHH-6911 - Write DiscriminatorValue to DiscriminatorColumn when combined with InheritanceType#JOINED
This commit is contained in:
parent
e64e89b2cc
commit
5329bba1ea
|
@ -40,6 +40,7 @@ import javax.persistence.Basic;
|
|||
import javax.persistence.Cacheable;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.ElementCollection;
|
||||
|
@ -97,6 +98,7 @@ import org.hibernate.annotations.CascadeType;
|
|||
import org.hibernate.annotations.Check;
|
||||
import org.hibernate.annotations.CollectionId;
|
||||
import org.hibernate.annotations.Columns;
|
||||
import org.hibernate.annotations.DiscriminatorFormula;
|
||||
import org.hibernate.annotations.DiscriminatorOptions;
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchProfile;
|
||||
|
@ -635,12 +637,27 @@ public final class AnnotationBinder {
|
|||
Ejb3JoinColumn[] inheritanceJoinedColumns = makeInheritanceJoinColumns(
|
||||
clazzToProcess, mappings, inheritanceState, superEntity
|
||||
);
|
||||
Ejb3DiscriminatorColumn discriminatorColumn = null;
|
||||
|
||||
final Ejb3DiscriminatorColumn discriminatorColumn;
|
||||
if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) {
|
||||
discriminatorColumn = processDiscriminatorProperties(
|
||||
clazzToProcess, mappings, inheritanceState, entityBinder
|
||||
discriminatorColumn = processSingleTableDiscriminatorProperties(
|
||||
clazzToProcess,
|
||||
mappings,
|
||||
inheritanceState,
|
||||
entityBinder
|
||||
);
|
||||
}
|
||||
else if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) {
|
||||
discriminatorColumn = processJoinedDiscriminatorProperties(
|
||||
clazzToProcess,
|
||||
mappings,
|
||||
inheritanceState,
|
||||
entityBinder
|
||||
);
|
||||
}
|
||||
else {
|
||||
discriminatorColumn = null;
|
||||
}
|
||||
|
||||
entityBinder.setProxy( clazzToProcess.getAnnotation( Proxy.class ) );
|
||||
entityBinder.setBatchSize( clazzToProcess.getAnnotation( BatchSize.class ) );
|
||||
|
@ -685,46 +702,71 @@ public final class AnnotationBinder {
|
|||
|
||||
OnDelete onDeleteAnn = clazzToProcess.getAnnotation( OnDelete.class );
|
||||
boolean onDeleteAppropriate = false;
|
||||
if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) && inheritanceState.hasParents() ) {
|
||||
onDeleteAppropriate = true;
|
||||
final JoinedSubclass jsc = ( JoinedSubclass ) persistentClass;
|
||||
SimpleValue key = new DependantValue( mappings, jsc.getTable(), jsc.getIdentifier() );
|
||||
jsc.setKey( key );
|
||||
ForeignKey fk = clazzToProcess.getAnnotation( ForeignKey.class );
|
||||
if ( fk != null && !BinderHelper.isEmptyAnnotationValue( fk.name() ) ) {
|
||||
key.setForeignKeyName( fk.name() );
|
||||
}
|
||||
if ( onDeleteAnn != null ) {
|
||||
key.setCascadeDeleteEnabled( OnDeleteAction.CASCADE.equals( onDeleteAnn.action() ) );
|
||||
}
|
||||
else {
|
||||
key.setCascadeDeleteEnabled( false );
|
||||
}
|
||||
//we are never in a second pass at that stage, so queue it
|
||||
SecondPass sp = new JoinedSubclassFkSecondPass( jsc, inheritanceJoinedColumns, key, mappings );
|
||||
mappings.addSecondPass( sp );
|
||||
mappings.addSecondPass( new CreateKeySecondPass( jsc ) );
|
||||
|
||||
// todo : sucks that this is separate from RootClass distinction
|
||||
final boolean isInheritanceRoot = !inheritanceState.hasParents();
|
||||
final boolean hasSubclasses = inheritanceState.hasSiblings();
|
||||
|
||||
if ( InheritanceType.JOINED.equals( inheritanceState.getType() ) ) {
|
||||
if ( inheritanceState.hasParents() ) {
|
||||
onDeleteAppropriate = true;
|
||||
final JoinedSubclass jsc = ( JoinedSubclass ) persistentClass;
|
||||
SimpleValue key = new DependantValue( mappings, jsc.getTable(), jsc.getIdentifier() );
|
||||
jsc.setKey( key );
|
||||
ForeignKey fk = clazzToProcess.getAnnotation( ForeignKey.class );
|
||||
if ( fk != null && !BinderHelper.isEmptyAnnotationValue( fk.name() ) ) {
|
||||
key.setForeignKeyName( fk.name() );
|
||||
}
|
||||
if ( onDeleteAnn != null ) {
|
||||
key.setCascadeDeleteEnabled( OnDeleteAction.CASCADE.equals( onDeleteAnn.action() ) );
|
||||
}
|
||||
else {
|
||||
key.setCascadeDeleteEnabled( false );
|
||||
}
|
||||
//we are never in a second pass at that stage, so queue it
|
||||
SecondPass sp = new JoinedSubclassFkSecondPass( jsc, inheritanceJoinedColumns, key, mappings );
|
||||
mappings.addSecondPass( sp );
|
||||
mappings.addSecondPass( new CreateKeySecondPass( jsc ) );
|
||||
}
|
||||
|
||||
if ( isInheritanceRoot ) {
|
||||
// the class we are processing is the root of the hierarchy, see if we had a discriminator column
|
||||
// (it is perfectly valid for joined subclasses to not have discriminators).
|
||||
if ( discriminatorColumn != null ) {
|
||||
// we have a discriminator column
|
||||
if ( hasSubclasses || !discriminatorColumn.isImplicit() ) {
|
||||
bindDiscriminatorColumnToRootPersistentClass(
|
||||
(RootClass) persistentClass,
|
||||
discriminatorColumn,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
mappings
|
||||
);
|
||||
//bind it again since the type might have changed
|
||||
entityBinder.bindDiscriminatorValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) {
|
||||
if ( ! inheritanceState.hasParents() ) {
|
||||
if ( inheritanceState.hasSiblings() || !discriminatorColumn.isImplicit() ) {
|
||||
//need a discriminator column
|
||||
bindDiscriminatorToPersistentClass(
|
||||
( RootClass ) persistentClass,
|
||||
if ( isInheritanceRoot ) {
|
||||
if ( hasSubclasses || !discriminatorColumn.isImplicit() ) {
|
||||
bindDiscriminatorColumnToRootPersistentClass(
|
||||
(RootClass) persistentClass,
|
||||
discriminatorColumn,
|
||||
entityBinder.getSecondaryTables(),
|
||||
propertyHolder,
|
||||
mappings
|
||||
);
|
||||
entityBinder.bindDiscriminatorValue();//bind it again since the type might have changed
|
||||
//bind it again since the type might have changed
|
||||
entityBinder.bindDiscriminatorValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( InheritanceType.TABLE_PER_CLASS.equals( inheritanceState.getType() ) ) {
|
||||
//nothing to do
|
||||
|
||||
if ( onDeleteAnn != null && !onDeleteAppropriate ) {
|
||||
LOG.invalidOnDeleteAnnotation(propertyHolder.getEntityName());
|
||||
}
|
||||
if (onDeleteAnn != null && !onDeleteAppropriate) LOG.invalidOnDeleteAnnotation(propertyHolder.getEntityName());
|
||||
|
||||
// try to find class level generators
|
||||
HashMap<String, IdGenerator> classGenerators = buildLocalGenerators( clazzToProcess, mappings );
|
||||
|
@ -782,32 +824,43 @@ public final class AnnotationBinder {
|
|||
entityBinder.processComplementaryTableDefinitions( tabAnn );
|
||||
}
|
||||
|
||||
// parse everything discriminator column relevant in case of single table inheritance
|
||||
private static Ejb3DiscriminatorColumn processDiscriminatorProperties(XClass clazzToProcess, Mappings mappings, InheritanceState inheritanceState, EntityBinder entityBinder) {
|
||||
/**
|
||||
* Process all discriminator-related metadata per rules for "single table" inheritance
|
||||
*/
|
||||
private static Ejb3DiscriminatorColumn processSingleTableDiscriminatorProperties(
|
||||
XClass clazzToProcess,
|
||||
Mappings mappings,
|
||||
InheritanceState inheritanceState,
|
||||
EntityBinder entityBinder) {
|
||||
final boolean isRoot = !inheritanceState.hasParents();
|
||||
|
||||
Ejb3DiscriminatorColumn discriminatorColumn = null;
|
||||
javax.persistence.DiscriminatorColumn discAnn = clazzToProcess.getAnnotation(
|
||||
javax.persistence.DiscriminatorColumn.class
|
||||
);
|
||||
DiscriminatorType discriminatorType = discAnn != null ?
|
||||
discAnn.discriminatorType() :
|
||||
DiscriminatorType.STRING;
|
||||
DiscriminatorType discriminatorType = discAnn != null
|
||||
? discAnn.discriminatorType()
|
||||
: DiscriminatorType.STRING;
|
||||
|
||||
org.hibernate.annotations.DiscriminatorFormula discFormulaAnn = clazzToProcess.getAnnotation(
|
||||
org.hibernate.annotations.DiscriminatorFormula.class
|
||||
);
|
||||
if ( !inheritanceState.hasParents() ) {
|
||||
if ( isRoot ) {
|
||||
discriminatorColumn = Ejb3DiscriminatorColumn.buildDiscriminatorColumn(
|
||||
discriminatorType, discAnn, discFormulaAnn, mappings
|
||||
discriminatorType,
|
||||
discAnn,
|
||||
discFormulaAnn,
|
||||
mappings
|
||||
);
|
||||
}
|
||||
if ( discAnn != null && inheritanceState.hasParents() ) {
|
||||
if ( discAnn != null && !isRoot ) {
|
||||
LOG.invalidDiscriminatorAnnotation( clazzToProcess.getName() );
|
||||
}
|
||||
|
||||
String discrimValue = clazzToProcess.isAnnotationPresent( DiscriminatorValue.class ) ?
|
||||
clazzToProcess.getAnnotation( DiscriminatorValue.class ).value() :
|
||||
null;
|
||||
entityBinder.setDiscriminatorValue( discrimValue );
|
||||
final String discriminatorValue = clazzToProcess.isAnnotationPresent( DiscriminatorValue.class )
|
||||
? clazzToProcess.getAnnotation( DiscriminatorValue.class ).value()
|
||||
: null;
|
||||
entityBinder.setDiscriminatorValue( discriminatorValue );
|
||||
|
||||
DiscriminatorOptions discriminatorOptions = clazzToProcess.getAnnotation( DiscriminatorOptions.class );
|
||||
if ( discriminatorOptions != null) {
|
||||
|
@ -818,6 +871,53 @@ public final class AnnotationBinder {
|
|||
return discriminatorColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all discriminator-related metadata per rules for "joined" inheritance
|
||||
*/
|
||||
private static Ejb3DiscriminatorColumn processJoinedDiscriminatorProperties(
|
||||
XClass clazzToProcess,
|
||||
Mappings mappings,
|
||||
InheritanceState inheritanceState,
|
||||
EntityBinder entityBinder) {
|
||||
if ( clazzToProcess.isAnnotationPresent( DiscriminatorFormula.class ) ) {
|
||||
throw new MappingException( "@DiscriminatorFormula on joined inheritance not supported at this time" );
|
||||
}
|
||||
|
||||
|
||||
// DiscriminatorValue handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
final DiscriminatorValue discriminatorValueAnnotation = clazzToProcess.getAnnotation( DiscriminatorValue.class );
|
||||
final String discriminatorValue = discriminatorValueAnnotation != null
|
||||
? clazzToProcess.getAnnotation( DiscriminatorValue.class ).value()
|
||||
: null;
|
||||
entityBinder.setDiscriminatorValue( discriminatorValue );
|
||||
|
||||
|
||||
// DiscriminatorColumn handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
final DiscriminatorColumn discriminatorColumnAnnotation = clazzToProcess.getAnnotation( DiscriminatorColumn.class );
|
||||
if ( !inheritanceState.hasParents() ) {
|
||||
if ( discriminatorColumnAnnotation != null || mappings.useImplicitDiscriminatorColumnForJoinedInheritance() ) {
|
||||
final DiscriminatorType discriminatorType = discriminatorColumnAnnotation != null
|
||||
? discriminatorColumnAnnotation.discriminatorType()
|
||||
: DiscriminatorType.STRING;
|
||||
return Ejb3DiscriminatorColumn.buildDiscriminatorColumn(
|
||||
discriminatorType,
|
||||
discriminatorColumnAnnotation,
|
||||
null,
|
||||
mappings
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( discriminatorColumnAnnotation != null ) {
|
||||
LOG.invalidDiscriminatorAnnotation( clazzToProcess.getName() );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void processIdPropertiesIfNotAlready(
|
||||
Map<XClass, InheritanceState> inheritanceStatePerClass,
|
||||
Mappings mappings,
|
||||
|
@ -1375,7 +1475,7 @@ public final class AnnotationBinder {
|
|||
}
|
||||
|
||||
|
||||
private static void bindDiscriminatorToPersistentClass(
|
||||
private static void bindDiscriminatorColumnToRootPersistentClass(
|
||||
RootClass rootClass,
|
||||
Ejb3DiscriminatorColumn discriminatorColumn,
|
||||
Map<String, Join> secondaryTables,
|
||||
|
@ -1387,10 +1487,10 @@ public final class AnnotationBinder {
|
|||
}
|
||||
discriminatorColumn.setJoins( secondaryTables );
|
||||
discriminatorColumn.setPropertyHolder( propertyHolder );
|
||||
SimpleValue discrim = new SimpleValue( mappings, rootClass.getTable() );
|
||||
rootClass.setDiscriminator( discrim );
|
||||
discriminatorColumn.linkWithValue( discrim );
|
||||
discrim.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
|
||||
SimpleValue discriminatorColumnBinding = new SimpleValue( mappings, rootClass.getTable() );
|
||||
rootClass.setDiscriminator( discriminatorColumnBinding );
|
||||
discriminatorColumn.linkWithValue( discriminatorColumnBinding );
|
||||
discriminatorColumnBinding.setTypeName( discriminatorColumn.getDiscriminatorTypeName() );
|
||||
rootClass.setPolymorphic( true );
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev( "Setting discriminator for entity {0}", rootClass.getEntityName() );
|
||||
|
|
|
@ -604,6 +604,21 @@ public interface AvailableSettings {
|
|||
|
||||
String FORCE_DISCRIMINATOR_IN_SELECTS_BY_DEFAULT = "hibernate.discriminator.force_in_select";
|
||||
|
||||
/**
|
||||
* The legacy behavior of Hibernate is to not use discriminators for joined inheritance (Hibernate does not need
|
||||
* the discriminator...). However, some JPA providers do need the discriminator for handling joined inheritance.
|
||||
* In the interest of portability this capability has been added to Hibernate too.
|
||||
* <p/>
|
||||
* However, we want to make sure that legacy applications continue to work as well. Which puts us in a bind in
|
||||
* terms of how to handle "implicit" discriminator mappings. The solution is to assume that the absence of
|
||||
* discriminator metadata means to follow the legacy behavior *unless* this setting is enabled. With this setting
|
||||
* enabled, Hibernate will interpret the absence of discriminator metadata as an indication to use the JPA
|
||||
* defined defaults for these absent annotations.
|
||||
*
|
||||
* See Hibernate Jira issue HHH-6911 for additional background info,
|
||||
*/
|
||||
String IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS = "hibernate.discriminator.implicit_for_joined";
|
||||
|
||||
String ENABLE_LAZY_LOAD_NO_TRANS = "hibernate.enable_lazy_load_no_trans";
|
||||
|
||||
String HQL_BULK_ID_STRATEGY = "hibernate.hql.bulk_id_strategy";
|
||||
|
@ -678,4 +693,5 @@ public interface AvailableSettings {
|
|||
String LOG_SESSION_METRICS = "hibernate.session.events.log";
|
||||
|
||||
String AUTO_SESSION_EVENTS_LISTENER = "hibernate.session.events.auto";
|
||||
|
||||
}
|
||||
|
|
|
@ -3375,6 +3375,7 @@ public class Configuration implements Serializable {
|
|||
}
|
||||
|
||||
private Boolean useNewGeneratorMappings;
|
||||
|
||||
@Override
|
||||
public boolean useNewGeneratorMappings() {
|
||||
if ( useNewGeneratorMappings == null ) {
|
||||
|
@ -3385,6 +3386,20 @@ public class Configuration implements Serializable {
|
|||
return useNewGeneratorMappings;
|
||||
}
|
||||
|
||||
|
||||
private Boolean implicitDiscriminatorColumnForJoinedInheritance;
|
||||
|
||||
@Override
|
||||
public boolean useImplicitDiscriminatorColumnForJoinedInheritance() {
|
||||
if ( implicitDiscriminatorColumnForJoinedInheritance == null ) {
|
||||
final String booleanName = getConfigurationProperties()
|
||||
.getProperty( AvailableSettings.IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS );
|
||||
implicitDiscriminatorColumnForJoinedInheritance = Boolean.valueOf( booleanName );
|
||||
}
|
||||
return implicitDiscriminatorColumnForJoinedInheritance;
|
||||
}
|
||||
|
||||
|
||||
private Boolean useNationalizedCharacterData;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -34,8 +34,8 @@ import org.hibernate.annotations.DiscriminatorFormula;
|
|||
* @author Emmanuel Bernard
|
||||
*/
|
||||
public class Ejb3DiscriminatorColumn extends Ejb3Column {
|
||||
private static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "DTYPE";
|
||||
private static final String DEFAULT_DISCRIMINATOR_TYPE = "string";
|
||||
public static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "DTYPE";
|
||||
public static final String DEFAULT_DISCRIMINATOR_TYPE = "string";
|
||||
private static final int DEFAULT_DISCRIMINATOR_LENGTH = 31;
|
||||
|
||||
private String discriminatorTypeName;
|
||||
|
|
|
@ -797,6 +797,17 @@ public interface Mappings {
|
|||
*/
|
||||
public boolean useNewGeneratorMappings();
|
||||
|
||||
/**
|
||||
* Should we handle discriminators for joined inheritance per legacy Hibernate rules, or
|
||||
* Should we use the new generator strategy mappings. This is controlled by the
|
||||
* {@link AvailableSettings#USE_NEW_ID_GENERATOR_MAPPINGS} setting.
|
||||
*
|
||||
* @return True if the new generators should be used, false otherwise.
|
||||
*
|
||||
* @see AvailableSettings#IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS
|
||||
*/
|
||||
public boolean useImplicitDiscriminatorColumnForJoinedInheritance();
|
||||
|
||||
/**
|
||||
* Should we use nationalized variants of character data by default? This is controlled by the
|
||||
* {@link AvailableSettings#USE_NATIONALIZED_CHARACTER_DATA} setting.
|
||||
|
|
|
@ -43,8 +43,10 @@ import org.hibernate.engine.spi.Mapping;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.DynamicFilterAliasGenerator;
|
||||
import org.hibernate.internal.FilterAliasGenerator;
|
||||
import org.hibernate.internal.util.MarkerObject;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Formula;
|
||||
import org.hibernate.mapping.Join;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
|
@ -53,11 +55,16 @@ import org.hibernate.mapping.Property;
|
|||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.binding.EntityBinding;
|
||||
import org.hibernate.sql.CaseFragment;
|
||||
import org.hibernate.sql.InFragment;
|
||||
import org.hibernate.sql.Insert;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.*;
|
||||
import org.hibernate.type.DiscriminatorType;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* An <tt>EntityPersister</tt> implementing the normalized "table-per-subclass"
|
||||
|
@ -66,6 +73,13 @@ import org.hibernate.type.Type;
|
|||
* @author Gavin King
|
||||
*/
|
||||
public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||
private static final Logger log = Logger.getLogger( JoinedSubclassEntityPersister.class );
|
||||
|
||||
private static final String IMPLICIT_DISCRIMINATOR_ALIAS = "clazz_";
|
||||
private static final Object NULL_DISCRIMINATOR = new MarkerObject("<null discriminator>");
|
||||
private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject("<not null discriminator>");
|
||||
private static final String NULL_STRING = "null";
|
||||
private static final String NOT_NULL_STRING = "not null";
|
||||
|
||||
// the class hierarchy structure
|
||||
private final int tableSpan;
|
||||
|
@ -116,6 +130,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
|
||||
private final Object discriminatorValue;
|
||||
private final String discriminatorSQLString;
|
||||
private final DiscriminatorType discriminatorType;
|
||||
private final String explicitDiscriminatorColumnName;
|
||||
private final String discriminatorAlias;
|
||||
|
||||
// Span of the tables directly mapped by this entity and super-classes, if any
|
||||
private final int coreTableSpan;
|
||||
|
@ -136,15 +153,58 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
// DISCRIMINATOR
|
||||
|
||||
if ( persistentClass.isPolymorphic() ) {
|
||||
try {
|
||||
discriminatorValue = persistentClass.getSubclassId();
|
||||
discriminatorSQLString = discriminatorValue.toString();
|
||||
final Value discriminatorMapping = persistentClass.getDiscriminator();
|
||||
if ( discriminatorMapping != null ) {
|
||||
log.debug( "Encountered explicit discriminator mapping for joined inheritance" );
|
||||
|
||||
final Selectable selectable = discriminatorMapping.getColumnIterator().next();
|
||||
if ( Formula.class.isInstance( selectable ) ) {
|
||||
throw new MappingException( "Discriminator formulas on joined inheritance hierarchies not supported at this time" );
|
||||
}
|
||||
else {
|
||||
final Column column = (Column) selectable;
|
||||
explicitDiscriminatorColumnName = column.getQuotedName( factory.getDialect() );
|
||||
discriminatorAlias = column.getAlias( factory.getDialect(), persistentClass.getRootTable() );
|
||||
}
|
||||
discriminatorType = (DiscriminatorType) persistentClass.getDiscriminator().getType();
|
||||
if ( persistentClass.isDiscriminatorValueNull() ) {
|
||||
discriminatorValue = NULL_DISCRIMINATOR;
|
||||
discriminatorSQLString = InFragment.NULL;
|
||||
}
|
||||
else if ( persistentClass.isDiscriminatorValueNotNull() ) {
|
||||
discriminatorValue = NOT_NULL_DISCRIMINATOR;
|
||||
discriminatorSQLString = InFragment.NOT_NULL;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
discriminatorValue = discriminatorType.stringToObject( persistentClass.getDiscriminatorValue() );
|
||||
discriminatorSQLString = discriminatorType.objectToSQLString( discriminatorValue, factory.getDialect() );
|
||||
}
|
||||
catch (ClassCastException cce) {
|
||||
throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException("Could not format discriminator value to SQL string", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new MappingException( "Could not format discriminator value to SQL string", e );
|
||||
else {
|
||||
explicitDiscriminatorColumnName = null;
|
||||
discriminatorAlias = IMPLICIT_DISCRIMINATOR_ALIAS;
|
||||
discriminatorType = StandardBasicTypes.INTEGER;
|
||||
try {
|
||||
discriminatorValue = persistentClass.getSubclassId();
|
||||
discriminatorSQLString = discriminatorValue.toString();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new MappingException( "Could not format discriminator value to SQL string", e );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
explicitDiscriminatorColumnName = null;
|
||||
discriminatorAlias = IMPLICIT_DISCRIMINATOR_ALIAS;
|
||||
discriminatorType = StandardBasicTypes.INTEGER;
|
||||
discriminatorValue = null;
|
||||
discriminatorSQLString = null;
|
||||
}
|
||||
|
@ -477,12 +537,35 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
subclassClosure[k] = sc.getEntityName();
|
||||
try {
|
||||
if ( persistentClass.isPolymorphic() ) {
|
||||
// we now use subclass ids that are consistent across all
|
||||
// persisters for a class hierarchy, so that the use of
|
||||
// "foo.class = Bar" works in HQL
|
||||
Integer subclassId = sc.getSubclassId();
|
||||
subclassesByDiscriminatorValue.put( subclassId, sc.getEntityName() );
|
||||
discriminatorValues[k] = subclassId.toString();
|
||||
final Object discriminatorValue;
|
||||
if ( explicitDiscriminatorColumnName != null ) {
|
||||
if ( sc.isDiscriminatorValueNull() ) {
|
||||
discriminatorValue = NULL_DISCRIMINATOR;
|
||||
}
|
||||
else if ( sc.isDiscriminatorValueNotNull() ) {
|
||||
discriminatorValue = NOT_NULL_DISCRIMINATOR;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
discriminatorValue = discriminatorType.stringToObject( sc.getDiscriminatorValue() );
|
||||
}
|
||||
catch (ClassCastException cce) {
|
||||
throw new MappingException( "Illegal discriminator type: " + discriminatorType.getName() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MappingException( "Could not format discriminator value to SQL string", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we now use subclass ids that are consistent across all
|
||||
// persisters for a class hierarchy, so that the use of
|
||||
// "foo.class = Bar" works in HQL
|
||||
discriminatorValue = sc.getSubclassId();
|
||||
}
|
||||
|
||||
subclassesByDiscriminatorValue.put( discriminatorValue, sc.getEntityName() );
|
||||
discriminatorValues[k] = discriminatorValue.toString();
|
||||
int id = getTableId(
|
||||
sc.getTable().getQualifiedName(
|
||||
factory.getDialect(),
|
||||
|
@ -702,6 +785,9 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
constraintOrderedKeyColumnNames = null;
|
||||
discriminatorValue = null;
|
||||
discriminatorSQLString = null;
|
||||
discriminatorType = StandardBasicTypes.INTEGER;
|
||||
explicitDiscriminatorColumnName = null;
|
||||
discriminatorAlias = IMPLICIT_DISCRIMINATOR_ALIAS;
|
||||
coreTableSpan = -1;
|
||||
isNullableTable = null;
|
||||
subclassNamesBySubclassTable = null;
|
||||
|
@ -729,21 +815,50 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
}
|
||||
|
||||
public Type getDiscriminatorType() {
|
||||
return StandardBasicTypes.INTEGER;
|
||||
return discriminatorType;
|
||||
}
|
||||
|
||||
public Object getDiscriminatorValue() {
|
||||
return discriminatorValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscriminatorSQLValue() {
|
||||
return discriminatorSQLString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscriminatorColumnName() {
|
||||
return explicitDiscriminatorColumnName == null
|
||||
? super.getDiscriminatorColumnName()
|
||||
: explicitDiscriminatorColumnName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscriminatorColumnReaders() {
|
||||
return getDiscriminatorColumnName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscriminatorColumnReaderTemplate() {
|
||||
return getDiscriminatorColumnName();
|
||||
}
|
||||
|
||||
protected String getDiscriminatorAlias() {
|
||||
return discriminatorAlias;
|
||||
}
|
||||
|
||||
public String getSubclassForDiscriminatorValue(Object value) {
|
||||
return (String) subclassesByDiscriminatorValue.get( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDiscriminatorToInsert(Insert insert) {
|
||||
if ( explicitDiscriminatorColumnName != null ) {
|
||||
insert.addColumn( explicitDiscriminatorColumnName, getDiscriminatorSQLValue() );
|
||||
}
|
||||
}
|
||||
|
||||
public Serializable[] getPropertySpaces() {
|
||||
return spaces; // don't need subclass tables, because they can't appear in conditions
|
||||
}
|
||||
|
@ -858,7 +973,12 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
|
||||
public void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
|
||||
if ( hasSubclasses() ) {
|
||||
select.setExtraSelectList( discriminatorFragment( name ), getDiscriminatorAlias() );
|
||||
if ( explicitDiscriminatorColumnName == null ) {
|
||||
select.setExtraSelectList( discriminatorFragment( name ), getDiscriminatorAlias() );
|
||||
}
|
||||
else {
|
||||
select.addColumn( name, explicitDiscriminatorColumnName, discriminatorAlias );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package org.hibernate.test.joinedsubclass;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.ExtraAssertions;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-6911" )
|
||||
public class JoinedSubclassWithExplicitDiscriminatorTest extends BaseCoreFunctionalTestCase {
|
||||
@Entity( name = "Animal" )
|
||||
@Table( name = "animal" )
|
||||
@Inheritance( strategy = InheritanceType.JOINED )
|
||||
@DiscriminatorColumn( name = "type", discriminatorType = DiscriminatorType.STRING )
|
||||
@DiscriminatorValue( value = "???animal???" )
|
||||
public static abstract class Animal {
|
||||
@Id
|
||||
public Integer id;
|
||||
|
||||
protected Animal() {
|
||||
}
|
||||
|
||||
protected Animal(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Cat" )
|
||||
@DiscriminatorValue( value = "cat" )
|
||||
public static class Cat extends Animal {
|
||||
public Cat() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Cat(Integer id) {
|
||||
super( id );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Dog" )
|
||||
@DiscriminatorValue( value = "dog" )
|
||||
public static class Dog extends Animal {
|
||||
public Dog() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Dog(Integer id) {
|
||||
super( id );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Animal.class, Cat.class, Dog.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataAssertions() {
|
||||
EntityPersister p = sessionFactory().getEntityPersister( Dog.class.getName() );
|
||||
assertNotNull( p );
|
||||
final JoinedSubclassEntityPersister dogPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
|
||||
assertEquals( "string", dogPersister.getDiscriminatorType().getName() );
|
||||
assertEquals( "type", dogPersister.getDiscriminatorColumnName() );
|
||||
assertEquals( "dog", dogPersister.getDiscriminatorValue() );
|
||||
|
||||
p = sessionFactory().getEntityPersister( Cat.class.getName() );
|
||||
assertNotNull( p );
|
||||
final JoinedSubclassEntityPersister catPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
|
||||
assertEquals( "string", catPersister.getDiscriminatorType().getName() );
|
||||
assertEquals( "type", catPersister.getDiscriminatorColumnName() );
|
||||
assertEquals( "cat", catPersister.getDiscriminatorValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicUsageTest() {
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
session.save( new Cat( 1 ) );
|
||||
session.save( new Dog( 2 ) );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.createQuery( "from Animal" ).list();
|
||||
Cat cat = (Cat) session.get( Cat.class, 1 );
|
||||
assertNotNull( cat );
|
||||
session.delete( cat );
|
||||
Dog dog = (Dog) session.get( Dog.class, 2 );
|
||||
assertNotNull( dog );
|
||||
session.delete( dog );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package org.hibernate.test.joinedsubclass;
|
||||
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Ejb3DiscriminatorColumn;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-6911" )
|
||||
public class JoinedSubclassWithImplicitDiscriminatorTest extends BaseCoreFunctionalTestCase {
|
||||
@Entity( name = "Animal" )
|
||||
@Table( name = "animal" )
|
||||
@Inheritance( strategy = InheritanceType.JOINED )
|
||||
public static abstract class Animal {
|
||||
@Id
|
||||
public Integer id;
|
||||
|
||||
protected Animal() {
|
||||
}
|
||||
|
||||
protected Animal(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Cat" )
|
||||
public static class Cat extends Animal {
|
||||
public Cat() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Cat(Integer id) {
|
||||
super( id );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity( name = "Dog" )
|
||||
public static class Dog extends Animal {
|
||||
public Dog() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Dog(Integer id) {
|
||||
super( id );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Animal.class, Cat.class, Dog.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.configure( configuration );
|
||||
configuration.setProperty( AvailableSettings.IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS, "true" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void metadataAssertions() {
|
||||
EntityPersister p = sessionFactory().getEntityPersister( Dog.class.getName() );
|
||||
assertNotNull( p );
|
||||
final JoinedSubclassEntityPersister dogPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
|
||||
assertEquals( Ejb3DiscriminatorColumn.DEFAULT_DISCRIMINATOR_TYPE, dogPersister.getDiscriminatorType().getName() );
|
||||
assertEquals( Ejb3DiscriminatorColumn.DEFAULT_DISCRIMINATOR_COLUMN_NAME, dogPersister.getDiscriminatorColumnName() );
|
||||
assertEquals( "Dog", dogPersister.getDiscriminatorValue() );
|
||||
|
||||
p = sessionFactory().getEntityPersister( Cat.class.getName() );
|
||||
assertNotNull( p );
|
||||
final JoinedSubclassEntityPersister catPersister = assertTyping( JoinedSubclassEntityPersister.class, p );
|
||||
assertEquals( Ejb3DiscriminatorColumn.DEFAULT_DISCRIMINATOR_TYPE, catPersister.getDiscriminatorType().getName() );
|
||||
assertEquals( Ejb3DiscriminatorColumn.DEFAULT_DISCRIMINATOR_COLUMN_NAME, catPersister.getDiscriminatorColumnName() );
|
||||
assertEquals( "Cat", catPersister.getDiscriminatorValue() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicUsageTest() {
|
||||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
session.save( new Cat( 1 ) );
|
||||
session.save( new Dog( 2 ) );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
session.beginTransaction();
|
||||
session.createQuery( "from Animal" ).list();
|
||||
Cat cat = (Cat) session.get( Cat.class, 1 );
|
||||
assertNotNull( cat );
|
||||
session.delete( cat );
|
||||
Dog dog = (Dog) session.get( Dog.class, 2 );
|
||||
assertNotNull( dog );
|
||||
session.delete( dog );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue