Skip to content

Commit 3844a34

Browse files
dreab8beikov
authored andcommitted
HHH-17587 Setting to null a property from a @SecondaryTable and @DynamicUpdate deletes the whole entry from database
1 parent 74f0181 commit 3844a34

File tree

7 files changed

+74
-12
lines changed

7 files changed

+74
-12
lines changed

hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,6 +3479,8 @@ private static class TableMappingBuilder {
34793479
private final Expectation deleteExpectation;
34803480
private final String customDeleteSql;
34813481
private final boolean deleteCallable;
3482+
private final boolean dynamicUpdate;
3483+
private final boolean dynamicInsert;
34823484

34833485
private final List<Integer> attributeIndexes = new ArrayList<>();
34843486

@@ -3498,7 +3500,9 @@ public TableMappingBuilder(
34983500
boolean cascadeDeleteEnabled,
34993501
Expectation deleteExpectation,
35003502
String customDeleteSql,
3501-
boolean deleteCallable) {
3503+
boolean deleteCallable,
3504+
boolean dynamicUpdate,
3505+
boolean dynamicInsert) {
35023506
this.tableName = tableName;
35033507
this.relativePosition = relativePosition;
35043508
this.keyMapping = keyMapping;
@@ -3515,6 +3519,8 @@ public TableMappingBuilder(
35153519
this.deleteExpectation = deleteExpectation;
35163520
this.customDeleteSql = customDeleteSql;
35173521
this.deleteCallable = deleteCallable;
3522+
this.dynamicUpdate = dynamicUpdate;
3523+
this.dynamicInsert = dynamicInsert;
35183524
}
35193525

35203526
private EntityTableMapping build() {
@@ -3535,7 +3541,9 @@ private EntityTableMapping build() {
35353541
cascadeDeleteEnabled,
35363542
deleteExpectation,
35373543
customDeleteSql,
3538-
deleteCallable
3544+
deleteCallable,
3545+
dynamicUpdate,
3546+
dynamicInsert
35393547
);
35403548
}
35413549
}
@@ -3592,7 +3600,9 @@ protected EntityTableMapping[] buildTableMappings() {
35923600
isTableCascadeDeleteEnabled( relativePosition ),
35933601
deleteExpectations[ relativePosition ],
35943602
customDeleteSql,
3595-
deleteCallable[ relativePosition ]
3603+
deleteCallable[ relativePosition ],
3604+
entityMetamodel.isDynamicUpdate(),
3605+
entityMetamodel.isDynamicInsert()
35963606
);
35973607

35983608
tableBuilderMap.put( tableExpression, tableMappingBuilder );

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/EntityTableMapping.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,33 @@ public EntityTableMapping(
6565
boolean cascadeDeleteEnabled,
6666
Expectation deleteExpectation,
6767
String deleteCustomSql,
68-
boolean deleteCallable) {
68+
boolean deleteCallable,
69+
boolean dynamicUpdate,
70+
boolean dynamicInsert) {
6971
this.tableName = tableName;
7072
this.relativePosition = relativePosition;
7173
this.keyMapping = keyMapping;
7274
this.attributeIndexes = attributeIndexes;
73-
this.insertDetails = new MutationDetails( MutationType.INSERT, insertExpectation, insertCustomSql, insertCallable );
74-
this.updateDetails = new MutationDetails( MutationType.UPDATE, updateExpectation, updateCustomSql, updateCallable );
75-
this.deleteDetails = new MutationDetails( MutationType.DELETE, deleteExpectation, deleteCustomSql, deleteCallable );
75+
this.insertDetails = new MutationDetails(
76+
MutationType.INSERT,
77+
insertExpectation,
78+
insertCustomSql,
79+
insertCallable,
80+
dynamicInsert
81+
);
82+
this.updateDetails = new MutationDetails(
83+
MutationType.UPDATE,
84+
updateExpectation,
85+
updateCustomSql,
86+
updateCallable,
87+
dynamicUpdate
88+
);
89+
this.deleteDetails = new MutationDetails(
90+
MutationType.DELETE,
91+
deleteExpectation,
92+
deleteCustomSql,
93+
deleteCallable
94+
);
7695

7796
if ( isOptional ) {
7897
flags.set( Flag.OPTIONAL.ordinal() );

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateCoordinatorStandard.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ protected void performUpdate(
305305
);
306306

307307
//noinspection StatementWithEmptyBody
308-
if ( valuesAnalysis.tablesNeedingUpdate.isEmpty() ) {
308+
if ( valuesAnalysis.tablesNeedingUpdate.isEmpty() && valuesAnalysis.tablesNeedingDynamicUpdate.isEmpty() ) {
309309
// nothing to do
310310
}
311311
else if ( valuesAnalysis.needsDynamicUpdate() ) {
@@ -969,7 +969,9 @@ protected void doDynamicUpdate(
969969
if ( tableMapping.isOptional()
970970
&& !valuesAnalysis.tablesWithNonNullValues.contains( tableMapping ) ) {
971971
// the table is optional, and we have null values for all of its columns
972-
// todo (6.0) : technically we might need to delete row here
972+
if ( valuesAnalysis.dirtyAttributeIndexes.length > 0 ) {
973+
return true;
974+
}
973975
return false;
974976
}
975977
else {

hibernate-core/src/main/java/org/hibernate/persister/entity/mutation/UpdateValuesAnalysis.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public interface UpdateValuesAnalysis extends ValuesAnalysis {
4040
*/
4141
TableSet getTablesWithPreviousNonNullValues();
4242

43+
TableSet getTablesNeedingDynamicUpdate();
44+
4345
/**
4446
* Descriptors for the analysis of each attribute
4547
*/

hibernate-core/src/main/java/org/hibernate/sql/model/TableMapping.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,33 @@ class MutationDetails {
8181
private final Expectation expectation;
8282
private final String customSql;
8383
private final boolean callable;
84+
private final boolean dynamicMutation;
8485

8586
public MutationDetails(
8687
MutationType mutationType,
8788
Expectation expectation,
8889
String customSql,
8990
boolean callable) {
91+
this(
92+
mutationType,
93+
expectation,
94+
customSql,
95+
callable,
96+
false
97+
);
98+
}
99+
100+
public MutationDetails(
101+
MutationType mutationType,
102+
Expectation expectation,
103+
String customSql,
104+
boolean callable,
105+
boolean dynamicMutation) {
90106
this.mutationType = mutationType;
91107
this.expectation = expectation;
92108
this.customSql = customSql;
93109
this.callable = callable;
110+
this.dynamicMutation = dynamicMutation;
94111
}
95112

96113
/**
@@ -122,5 +139,10 @@ public String getCustomSql() {
122139
public boolean isCallable() {
123140
return callable;
124141
}
142+
143+
public boolean isDynamicMutation() {
144+
return dynamicMutation;
145+
}
125146
}
147+
126148
}

hibernate-core/src/main/java/org/hibernate/sql/model/internal/OptionalTableUpdate.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,15 @@ public void accept(SqlAstWalker walker) {
128128

129129
@Override
130130
public MutationOperation createMutationOperation(ValuesAnalysis valuesAnalysis, SessionFactoryImplementor factory) {
131-
if ( getMutatingTable().getTableMapping().getInsertDetails().getCustomSql() != null
132-
|| getMutatingTable().getTableMapping().getDeleteDetails().getCustomSql() != null ) {
131+
final TableMapping tableMapping = getMutatingTable().getTableMapping();
132+
if ( tableMapping.getInsertDetails().getCustomSql() != null
133+
|| tableMapping.getInsertDetails().isDynamicMutation()
134+
|| tableMapping.getDeleteDetails().getCustomSql() != null
135+
|| tableMapping.getUpdateDetails().getCustomSql() != null
136+
|| tableMapping.getUpdateDetails().isDynamicMutation() ) {
133137
// Fallback to the optional table mutation operation because we have to execute user specified SQL
138+
// and with dynamic update insert we have to avoid using merge for optional table because
139+
// it can cause the deletion of the row when an attribute is set to null
134140
return new OptionalTableUpdateOperation( getMutationTarget(), this, factory );
135141
}
136142
return factory.getJdbcServices().getDialect().createOptionalTableUpdateOperation(

hibernate-core/src/main/java/org/hibernate/sql/model/jdbc/OptionalTableUpdateOperation.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ public void performMutation(
127127
ValuesAnalysis incomingValuesAnalysis,
128128
SharedSessionContractImplementor session) {
129129
final UpdateValuesAnalysis valuesAnalysis = (UpdateValuesAnalysis) incomingValuesAnalysis;
130-
if ( !valuesAnalysis.getTablesNeedingUpdate().contains( tableMapping ) ) {
130+
if ( !valuesAnalysis.getTablesNeedingUpdate().contains( tableMapping )
131+
&& !valuesAnalysis.getTablesNeedingDynamicUpdate().contains( tableMapping ) ) {
131132
return;
132133
}
133134

0 commit comments

Comments
 (0)