HHH-15099 - Improve handling of associations marked with @NotFound

- support for NotFound on logical 1-1 defined on JoinTable
This commit is contained in:
Steve Ebersole 2022-03-04 23:17:43 -06:00
parent ed5831f482
commit 82feac6bd3
6 changed files with 28 additions and 9 deletions

View File

@ -2653,6 +2653,7 @@ public final class AnnotationBinder {
Cascade hibernateCascade = property.getAnnotation( Cascade.class ); Cascade hibernateCascade = property.getAnnotation( Cascade.class );
NotFound notFound = property.getAnnotation( NotFound.class ); NotFound notFound = property.getAnnotation( NotFound.class );
NotFoundAction notFoundAction = notFound == null ? null : notFound.action(); NotFoundAction notFoundAction = notFound == null ? null : notFound.action();
final boolean hasNotFoundAction = notFoundAction != null;
// MapsId means the columns belong to the pk; // MapsId means the columns belong to the pk;
// A @MapsId association (obviously) must be non-null when the entity is first persisted. // A @MapsId association (obviously) must be non-null when the entity is first persisted.
@ -2663,12 +2664,15 @@ public final class AnnotationBinder {
// @OneToOne(optional = true) with @PKJC makes the association optional. // @OneToOne(optional = true) with @PKJC makes the association optional.
final boolean mandatory = !ann.optional() final boolean mandatory = !ann.optional()
|| property.isAnnotationPresent( Id.class ) || property.isAnnotationPresent( Id.class )
|| property.isAnnotationPresent( MapsId.class ) && notFoundAction != NotFoundAction.IGNORE; || property.isAnnotationPresent( MapsId.class ) && !hasNotFoundAction;
matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, ann.fetch() ); matchIgnoreNotFoundWithFetchType( propertyHolder.getEntityName(), property.getName(), notFoundAction, ann.fetch() );
OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class ); OnDelete onDeleteAnn = property.getAnnotation( OnDelete.class );
JoinTable assocTable = propertyHolder.getJoinTable(property); JoinTable assocTable = propertyHolder.getJoinTable(property);
if ( assocTable != null ) { if ( assocTable != null ) {
Join join = propertyHolder.addJoin( assocTable, false ); Join join = propertyHolder.addJoin( assocTable, false );
if ( hasNotFoundAction ) {
join.disableForeignKeyCreation();
}
for ( AnnotatedJoinColumn joinColumn : joinColumns) { for ( AnnotatedJoinColumn joinColumn : joinColumns) {
joinColumn.setExplicitTableName( join.getTable().getName() ); joinColumn.setExplicitTableName( join.getTable().getName() );
} }

View File

@ -275,6 +275,11 @@ public class OneToOneSecondPass implements SecondPass {
join.setTable( originalJoin.getTable() ); join.setTable( originalJoin.getTable() );
join.setInverse( true ); join.setInverse( true );
DependantValue key = new DependantValue( buildingContext, join.getTable(), persistentClass.getIdentifier() ); DependantValue key = new DependantValue( buildingContext, join.getTable(), persistentClass.getIdentifier() );
if ( notFoundAction != null ) {
join.disableForeignKeyCreation();
}
//TODO support @ForeignKey //TODO support @ForeignKey
join.setKey( key ); join.setKey( key );
join.setSequentialSelect( false ); join.setSequentialSelect( false );

View File

@ -29,6 +29,5 @@ public class SecondaryTableSecondPass implements SecondPass {
public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException { public void doSecondPass(Map<String, PersistentClass> persistentClasses) throws MappingException {
entityBinder.finalSecondaryTableBinding( propertyHolder ); entityBinder.finalSecondaryTableBinding( propertyHolder );
} }
} }

View File

@ -29,6 +29,7 @@ public class Join implements AttributeContainer, Serializable {
private boolean sequentialSelect; private boolean sequentialSelect;
private boolean inverse; private boolean inverse;
private boolean optional; private boolean optional;
private boolean disableForeignKeyCreation;
// Custom SQL // Custom SQL
private String customSQLInsert; private String customSQLInsert;
@ -97,8 +98,15 @@ public class Join implements AttributeContainer, Serializable {
this.persistentClass = persistentClass; this.persistentClass = persistentClass;
} }
public void disableForeignKeyCreation() {
disableForeignKeyCreation = true;
}
public void createForeignKey() { public void createForeignKey() {
getKey().createForeignKeyOfEntity( persistentClass.getEntityName() ); final ForeignKey foreignKey = getKey().createForeignKeyOfEntity( persistentClass.getEntityName() );
if ( disableForeignKeyCreation ) {
foreignKey.disableCreation();
}
} }
public void createPrimaryKey() { public void createPrimaryKey() {

View File

@ -5,6 +5,7 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.mapping; package org.hibernate.mapping;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
@ -37,7 +38,7 @@ public interface KeyValue extends Value {
boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect); boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect);
void createForeignKeyOfEntity(String entityName); ForeignKey createForeignKeyOfEntity(String entityName);
boolean isCascadeDeleteEnabled(); boolean isCascadeDeleteEnabled();

View File

@ -16,6 +16,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import jakarta.persistence.AttributeConverter;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.FetchMode; import org.hibernate.FetchMode;
@ -60,8 +61,6 @@ import org.hibernate.type.descriptor.jdbc.NationalizedTypeMappings;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.DynamicParameterizedType; import org.hibernate.usertype.DynamicParameterizedType;
import jakarta.persistence.AttributeConverter;
/** /**
* Any value that maps to columns. * Any value that maps to columns.
* @author Gavin King * @author Gavin King
@ -321,11 +320,14 @@ public abstract class SimpleValue implements KeyValue {
public void createForeignKey() throws MappingException {} public void createForeignKey() throws MappingException {}
@Override @Override
public void createForeignKeyOfEntity(String entityName) { public ForeignKey createForeignKeyOfEntity(String entityName) {
if ( isConstrained() ) { if ( isConstrained() ) {
table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName, getForeignKeyDefinition() ) final ForeignKey fk = table.createForeignKey( getForeignKeyName(), getConstraintColumns(), entityName, getForeignKeyDefinition() );
.setCascadeDeleteEnabled(cascadeDeleteEnabled); fk.setCascadeDeleteEnabled( cascadeDeleteEnabled );
return fk;
} }
return null;
} }
@Override @Override