HHH-12445 Auto-detect when discriminator columns are nullable

This commit is contained in:
Yoann Rodière 2021-05-03 17:50:38 +02:00
parent 41c71bfed7
commit 7144af5990
4 changed files with 57 additions and 7 deletions

View File

@ -45,12 +45,6 @@ public class DiscriminatorNotNullSingleTableTest extends BaseEntityManagerFuncti
@Test @Test
public void test() { public void test() {
doInJPA( this::entityManagerFactory, entityManager -> { doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).doWork( connection -> {
try(Statement statement = connection.createStatement()) {
statement.executeUpdate( "ALTER TABLE Account ALTER COLUMN DTYPE SET NULL" );
}
} );
//tag::entity-inheritance-single-table-discriminator-value-persist-example[] //tag::entity-inheritance-single-table-discriminator-value-persist-example[]
DebitAccount debitAccount = new DebitAccount(); DebitAccount debitAccount = new DebitAccount();
debitAccount.setId( 1L ); debitAccount.setId( 1L );

View File

@ -8,7 +8,6 @@ package org.hibernate.cfg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
@ -146,6 +145,7 @@ import org.hibernate.cfg.annotations.PropertyBinder;
import org.hibernate.cfg.annotations.QueryBinder; import org.hibernate.cfg.annotations.QueryBinder;
import org.hibernate.cfg.annotations.SimpleValueBinder; import org.hibernate.cfg.annotations.SimpleValueBinder;
import org.hibernate.cfg.annotations.TableBinder; import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.cfg.internal.NullableDiscriminatorColumnSecondPass;
import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.FilterDefinition; import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.PersistentIdentifierGenerator;
@ -1484,6 +1484,8 @@ public final class AnnotationBinder {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Setting discriminator for entity {0}", rootClass.getEntityName() ); LOG.tracev( "Setting discriminator for entity {0}", rootClass.getEntityName() );
} }
context.getMetadataCollector().addSecondPass(
new NullableDiscriminatorColumnSecondPass( rootClass.getEntityName() ) );
} }
} }

View File

@ -71,6 +71,7 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.BinderHelper; import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3DiscriminatorColumn;
import org.hibernate.cfg.Ejb3JoinColumn; import org.hibernate.cfg.Ejb3JoinColumn;
import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.ObjectNameSource; import org.hibernate.cfg.ObjectNameSource;

View File

@ -0,0 +1,53 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cfg.internal;
import java.util.Iterator;
import java.util.Map;
import org.hibernate.MappingException;
import org.hibernate.cfg.SecondPass;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Selectable;
public class NullableDiscriminatorColumnSecondPass implements SecondPass {
private final String rootEntityName;
public NullableDiscriminatorColumnSecondPass(String rootEntityName) {
this.rootEntityName = rootEntityName;
}
@Override
@SuppressWarnings("rawtypes")
public void doSecondPass(Map persistentClasses) throws MappingException {
PersistentClass rootPersistenceClass = (PersistentClass) persistentClasses.get( rootEntityName );
if ( hasNullDiscriminatorValue( rootPersistenceClass ) ) {
for ( Iterator<Selectable> iterator = rootPersistenceClass.getDiscriminator().getColumnIterator();
iterator.hasNext(); ) {
Selectable selectable = iterator.next();
if ( selectable instanceof Column ) {
( (Column) selectable ).setNullable( true );
}
}
}
}
@SuppressWarnings({ "unchecked" })
private boolean hasNullDiscriminatorValue(PersistentClass rootPersistenceClass) {
if ( rootPersistenceClass.isDiscriminatorValueNull() ) {
return true;
}
Iterator<PersistentClass> subclassIterator = rootPersistenceClass.getSubclassIterator();
while ( subclassIterator.hasNext() ) {
if ( subclassIterator.next().isDiscriminatorValueNull() ) {
return true;
}
}
return false;
}
}