Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
HHH-19565 restore application of @SQLRestriction to @manytoone @joint…
…able

In this case, we won't set the FK to null. Instead, we can handle it with
an upsert (SQL MERGE).
  • Loading branch information
gavinking committed Jun 21, 2025
commit 201a03316dbe1529e4276d13d5638e4efb8fff34
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ private static org.hibernate.mapping.ManyToOne handleJoinTable(
notFoundAction,
value
) );
value.markAsJoinTable();
return value;
}
else {
Expand All @@ -270,7 +271,9 @@ private static org.hibernate.mapping.ManyToOne handleJoinTable(
join.disableForeignKeyCreation();
}
// All FK columns should be in the same table
return new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
var manyToOne = new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
manyToOne.markAsJoinTable();
return manyToOne;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
*/
public final class ManyToOne extends ToOne {
private boolean isLogicalOneToOne;
private boolean hasJoinTable;
private NotFoundAction notFoundAction;

private transient ManyToOneType resolvedType;
Expand Down Expand Up @@ -141,6 +142,14 @@ public boolean isLogicalOneToOne() {
return isLogicalOneToOne;
}

public void markAsJoinTable() {
hasJoinTable = true;
}

public boolean hasJoinTable() {
return hasJoinTable;
}

@Override
public boolean isNullable() {
return getReferencedPropertyName() != null || super.isNullable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ && equal( join.getKey(), manyToOne ) ) {
this.hasJoinTable = hasJoinTable;
}
else {
this.hasJoinTable = false;
this.hasJoinTable = manyToOne.hasJoinTable();
bidirectionalAttributeName = findBidirectionalOneToManyAttributeName(
propertyPath,
declaringType,
Expand Down Expand Up @@ -361,7 +361,7 @@ && equal( join.getKey(), manyToOne ) ) {
}
}
isOptional = manyToOne.isIgnoreNotFound();
isInternalLoadNullable = ( isNullable && bootValue.isForeignKeyEnabled() ) || hasNotFoundAction();
isInternalLoadNullable = isNullable && bootValue.isForeignKeyEnabled() || hasNotFoundAction();
}
else {
assert bootValue instanceof OneToOne;
Expand Down Expand Up @@ -412,12 +412,10 @@ the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does
so in order to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
*/
final OneToOne oneToOne = (OneToOne) bootValue;
if ( oneToOne.getMappedByProperty() == null ) {
this.bidirectionalAttributePath = SelectablePath.parse( referencedPropertyName );
}
else {
this.bidirectionalAttributePath = SelectablePath.parse( oneToOne.getMappedByProperty() );
}
this.bidirectionalAttributePath =
oneToOne.getMappedByProperty() == null
? SelectablePath.parse( referencedPropertyName )
: SelectablePath.parse( oneToOne.getMappedByProperty() );
notFoundAction = null;
isKeyTableNullable = isNullable();
isOptional = !bootValue.isConstrained();
Expand Down Expand Up @@ -628,10 +626,9 @@ else if ( value instanceof OneToOne oneToOne ) {
return null;
}

private static FetchTiming adjustFetchTiming(
FetchTiming mappedFetchTiming,
ToOne bootValue) {
return bootValue instanceof ManyToOne manyToOne && manyToOne.getNotFoundAction() != null
private static FetchTiming adjustFetchTiming(FetchTiming mappedFetchTiming, ToOne bootValue) {
return bootValue instanceof ManyToOne manyToOne
&& manyToOne.getNotFoundAction() != null
? FetchTiming.IMMEDIATE
: mappedFetchTiming;
}
Expand All @@ -641,9 +638,8 @@ private static TableGroupProducer resolveDeclaringTableGroupProducer(EntityPersi
NavigableRole parentRole = navigableRole.getParent();
String collectionRole = null;
do {
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact(
parentRole.getLocalName()
);
final CollectionPart.Nature nature =
CollectionPart.Nature.fromNameExact( parentRole.getLocalName() );
if (nature != null) {
collectionRole = parentRole.getParent().getFullPath();
break;
Expand Down Expand Up @@ -1175,11 +1171,10 @@ class Mother {
// If the parent is null, this is a simple collection fetch of a root, in which case the types must match
if ( parentPath.getParent() == null ) {
final String entityName = entityMappingType.getPartName();
return parentPath.getFullPath().startsWith( entityName ) && (
parentPath.getFullPath().length() == entityName.length()
// Ignore a possible alias
|| parentPath.getFullPath().charAt( entityName.length() ) == '('
);
return parentPath.getFullPath().startsWith( entityName )
&& ( parentPath.getFullPath().length() == entityName.length()
// Ignore a possible alias
|| parentPath.getFullPath().charAt( entityName.length() ) == '(' );
}
// If we have a parent, we ensure that the parent is the same as the attribute name
else {
Expand Down Expand Up @@ -2109,8 +2104,9 @@ public TableGroupJoin createTableGroupJoin(
// @SQLRestriction should not be applied when joining FK association,
// because that would result in us setting the FK to null when the
// owning entity is updated, that is, to data loss.
// But we'll let it apply on the TARGET side of a @OneToOne
if ( sideNature == ForeignKeyDescriptor.Nature.TARGET ) {
// But we let it apply on the TARGET side of a @OneToOne, and we apply
// it whenever there is a dedicated join table.
if ( hasJoinTable || sideNature == ForeignKeyDescriptor.Nature.TARGET ) {
associatedEntityMappingType.applyWhereRestrictions(
join::applyPredicate,
tableGroup,
Expand Down