Skip to content

Commit 201a033

Browse files
committed
HHH-19565 restore application of @SQLRestriction to @manytoone @jointable
In this case, we won't set the FK to null. Instead, we can handle it with an upsert (SQL MERGE).
1 parent d570c36 commit 201a033

File tree

3 files changed

+31
-23
lines changed

3 files changed

+31
-23
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ private static org.hibernate.mapping.ManyToOne handleJoinTable(
259259
notFoundAction,
260260
value
261261
) );
262+
value.markAsJoinTable();
262263
return value;
263264
}
264265
else {
@@ -270,7 +271,9 @@ private static org.hibernate.mapping.ManyToOne handleJoinTable(
270271
join.disableForeignKeyCreation();
271272
}
272273
// All FK columns should be in the same table
273-
return new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
274+
var manyToOne = new org.hibernate.mapping.ManyToOne( context, joinColumns.getTable() );
275+
manyToOne.markAsJoinTable();
276+
return manyToOne;
274277
}
275278
}
276279

hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020
public final class ManyToOne extends ToOne {
2121
private boolean isLogicalOneToOne;
22+
private boolean hasJoinTable;
2223
private NotFoundAction notFoundAction;
2324

2425
private transient ManyToOneType resolvedType;
@@ -141,6 +142,14 @@ public boolean isLogicalOneToOne() {
141142
return isLogicalOneToOne;
142143
}
143144

145+
public void markAsJoinTable() {
146+
hasJoinTable = true;
147+
}
148+
149+
public boolean hasJoinTable() {
150+
return hasJoinTable;
151+
}
152+
144153
@Override
145154
public boolean isNullable() {
146155
return getReferencedPropertyName() != null || super.isNullable();

hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ && equal( join.getKey(), manyToOne ) ) {
307307
this.hasJoinTable = hasJoinTable;
308308
}
309309
else {
310-
this.hasJoinTable = false;
310+
this.hasJoinTable = manyToOne.hasJoinTable();
311311
bidirectionalAttributeName = findBidirectionalOneToManyAttributeName(
312312
propertyPath,
313313
declaringType,
@@ -361,7 +361,7 @@ && equal( join.getKey(), manyToOne ) ) {
361361
}
362362
}
363363
isOptional = manyToOne.isIgnoreNotFound();
364-
isInternalLoadNullable = ( isNullable && bootValue.isForeignKeyEnabled() ) || hasNotFoundAction();
364+
isInternalLoadNullable = isNullable && bootValue.isForeignKeyEnabled() || hasNotFoundAction();
365365
}
366366
else {
367367
assert bootValue instanceof OneToOne;
@@ -412,12 +412,10 @@ the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does
412412
so in order to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
413413
*/
414414
final OneToOne oneToOne = (OneToOne) bootValue;
415-
if ( oneToOne.getMappedByProperty() == null ) {
416-
this.bidirectionalAttributePath = SelectablePath.parse( referencedPropertyName );
417-
}
418-
else {
419-
this.bidirectionalAttributePath = SelectablePath.parse( oneToOne.getMappedByProperty() );
420-
}
415+
this.bidirectionalAttributePath =
416+
oneToOne.getMappedByProperty() == null
417+
? SelectablePath.parse( referencedPropertyName )
418+
: SelectablePath.parse( oneToOne.getMappedByProperty() );
421419
notFoundAction = null;
422420
isKeyTableNullable = isNullable();
423421
isOptional = !bootValue.isConstrained();
@@ -628,10 +626,9 @@ else if ( value instanceof OneToOne oneToOne ) {
628626
return null;
629627
}
630628

631-
private static FetchTiming adjustFetchTiming(
632-
FetchTiming mappedFetchTiming,
633-
ToOne bootValue) {
634-
return bootValue instanceof ManyToOne manyToOne && manyToOne.getNotFoundAction() != null
629+
private static FetchTiming adjustFetchTiming(FetchTiming mappedFetchTiming, ToOne bootValue) {
630+
return bootValue instanceof ManyToOne manyToOne
631+
&& manyToOne.getNotFoundAction() != null
635632
? FetchTiming.IMMEDIATE
636633
: mappedFetchTiming;
637634
}
@@ -641,9 +638,8 @@ private static TableGroupProducer resolveDeclaringTableGroupProducer(EntityPersi
641638
NavigableRole parentRole = navigableRole.getParent();
642639
String collectionRole = null;
643640
do {
644-
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact(
645-
parentRole.getLocalName()
646-
);
641+
final CollectionPart.Nature nature =
642+
CollectionPart.Nature.fromNameExact( parentRole.getLocalName() );
647643
if (nature != null) {
648644
collectionRole = parentRole.getParent().getFullPath();
649645
break;
@@ -1175,11 +1171,10 @@ class Mother {
11751171
// If the parent is null, this is a simple collection fetch of a root, in which case the types must match
11761172
if ( parentPath.getParent() == null ) {
11771173
final String entityName = entityMappingType.getPartName();
1178-
return parentPath.getFullPath().startsWith( entityName ) && (
1179-
parentPath.getFullPath().length() == entityName.length()
1180-
// Ignore a possible alias
1181-
|| parentPath.getFullPath().charAt( entityName.length() ) == '('
1182-
);
1174+
return parentPath.getFullPath().startsWith( entityName )
1175+
&& ( parentPath.getFullPath().length() == entityName.length()
1176+
// Ignore a possible alias
1177+
|| parentPath.getFullPath().charAt( entityName.length() ) == '(' );
11831178
}
11841179
// If we have a parent, we ensure that the parent is the same as the attribute name
11851180
else {
@@ -2109,8 +2104,9 @@ public TableGroupJoin createTableGroupJoin(
21092104
// @SQLRestriction should not be applied when joining FK association,
21102105
// because that would result in us setting the FK to null when the
21112106
// owning entity is updated, that is, to data loss.
2112-
// But we'll let it apply on the TARGET side of a @OneToOne
2113-
if ( sideNature == ForeignKeyDescriptor.Nature.TARGET ) {
2107+
// But we let it apply on the TARGET side of a @OneToOne, and we apply
2108+
// it whenever there is a dedicated join table.
2109+
if ( hasJoinTable || sideNature == ForeignKeyDescriptor.Nature.TARGET ) {
21142110
associatedEntityMappingType.applyWhereRestrictions(
21152111
join::applyPredicate,
21162112
tableGroup,

0 commit comments

Comments
 (0)