Skip to content

Commit 856a001

Browse files
dreab8sebersole
authored andcommitted
HHH-18195 migration guide
1 parent fea3b2f commit 856a001

File tree

3 files changed

+60
-55
lines changed

3 files changed

+60
-55
lines changed

hibernate-core/src/test/java/org/hibernate/orm/test/collection/delayedOperation/BagDelayedOperationTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ public void testSimpleAddDetached(SessionFactoryScope scope) {
105105
Parent p = session.get( Parent.class, parentId );
106106
assertFalse( Hibernate.isInitialized( p.getChildren() ) );
107107
// add detached Child c
108-
session.lock( c1, LockOptions.NONE );
109-
p.addChild( c1 );
108+
p.addChild( session.merge( c1 ) );
110109
// collection should still be uninitialized
111110
assertFalse( Hibernate.isInitialized( p.getChildren() ) );
112111
}

hibernate-core/src/test/java/org/hibernate/orm/test/map/MapIndexFormulaTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
import java.util.List;
1010
import java.util.Map;
1111

12-
import org.hibernate.LockMode;
12+
import org.hibernate.dialect.MariaDBDialect;
1313

1414
import org.hibernate.testing.orm.junit.DomainModel;
1515
import org.hibernate.testing.orm.junit.SessionFactory;
1616
import org.hibernate.testing.orm.junit.SessionFactoryScope;
17+
import org.hibernate.testing.orm.junit.SkipForDialect;
1718
import org.junit.jupiter.api.AfterEach;
1819
import org.junit.jupiter.api.Test;
1920

@@ -58,6 +59,7 @@ public void testIndexFunctionOnManyToManyMap(SessionFactoryScope scope) {
5859
}
5960

6061
@Test
62+
@SkipForDialect( dialectClass = MariaDBDialect.class, reason = "HHH-18433")
6163
public void testIndexFormulaMap(SessionFactoryScope scope) {
6264
User turin = new User( "turin", "tiger" );
6365
scope.inTransaction(
@@ -90,8 +92,7 @@ public void testIndexFormulaMap(SessionFactoryScope scope) {
9092
assertEquals( 1, g.getUsers().size() );
9193
Map smap = ( (User) g.getUsers().get( "gavin" ) ).getSession();
9294
assertEquals( 1, smap.size() );
93-
session.lock( turin , LockMode.NONE);
94-
User gavin = (User) g.getUsers().put( "gavin", turin );
95+
User gavin = (User) g.getUsers().put( "gavin", session.merge( turin ) );
9596
session.remove( gavin );
9697
assertEquals(
9798
0l,

migration-guide.adoc

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -153,56 +153,6 @@ String isDefault();
153153
* Removed `org.hibernate.annotations.CascadeType.DELETE` in favor of `org.hibernate.annotations.CascadeType#REMOVE`
154154
* Removed the attribute value from `@DynamicInsert` and `@DynamicUpdate`
155155

156-
[WARNING]
157-
===
158-
The removal of `CascadeType.SAVE_UPDATE` slightly changes the persist and flush behaviour (not affecting application using `Entitymanager`) that now conforms with the Jakarta JPA specifications.
159-
160-
Persisting a transient entity with an associated detached entity where the association is annotated with cascade=all or cascade=persist throws an exception if the detached entity has not been re-associated with the the session using lock or merge.
161-
162-
The same happens when flushing a managed entity having an associated detached entity.
163-
164-
```
165-
@Entit
166-
class Parent {
167-
...
168-
169-
@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true)
170-
@LazyCollection(value = LazyCollectionOption.EXTRA)
171-
private Set<Child> children = new HashSet<>();
172-
}
173-
174-
@Entity
175-
class Child {
176-
177-
...
178-
179-
@Id
180-
@GeneratedValue(strategy = GenerationType.AUTO)
181-
private Long id;
182-
183-
@ManyToOne
184-
private Parent parent;
185-
}
186-
187-
188-
```
189-
190-
```
191-
// Being Child c1 detached.
192-
193-
scope.inTransaction(
194-
session -> {
195-
Parent parent = session.get( Parent.class, parentId );
196-
// add detached Child c
197-
parent.addChild( c1 );
198-
}
199-
);
200-
```
201-
will throw an `jakarta.persistence.EntityExistsException`
202-
203-
in order to fix the issue we can call `session.lock(c1,LockMode.NONE)` before adding `c1` to the `parent` or instead using `p.addChild( session.merge(c1) )`;
204-
205-
206156
[[ddl-implicit-datatype-timestamp]]
207157
== Default precision for timestamp on some databases
208158

@@ -244,6 +194,61 @@ one file at a time. This is now done across the entire set of `hbm.xml` files a
244194
While most users will never see this change, it might impact integrations which tie-in to
245195
XML processing.
246196

197+
[[flush-persist]]
198+
== Session flush and persist
199+
200+
The removal of `CascadeType.SAVE_UPDATE` slightly changes the persist and flush behaviour (not affecting application using `Entitymanager`) that now conforms with the Jakarta JPA specifications.
201+
202+
Persisting a transient entity or flushing a manged entity with an associated detached entity having the association annotated with `cascade = CascadeType.ALL` or `cascade = CascadeType.PERSIST` throws now an `jakarta.persistence.EntityExistsException` if the detached entity has not been re-associated with the the Session.
203+
204+
To re-associate the detached entity with the Session the `Session#merge` method can be used.
205+
206+
Consider the following model
207+
208+
```
209+
@Entity
210+
class Parent {
211+
212+
...
213+
214+
@OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true)
215+
@LazyCollection(value = LazyCollectionOption.EXTRA)
216+
private Set<Child> children = new HashSet<>();
217+
218+
public void addChild(Child child) {
219+
children.add( child );
220+
child.setParent( this );
221+
}
222+
}
223+
224+
@Entity
225+
class Child {
226+
227+
...
228+
229+
@Id
230+
@GeneratedValue(strategy = GenerationType.AUTO)
231+
private Long id;
232+
233+
@ManyToOne
234+
private Parent parent;
235+
}
236+
237+
```
238+
239+
Assuming we have c1 as a detached Child, the following code will now result in jakarta.persistence.EntityExistsException being thrown at flush time:
240+
241+
```
242+
Parent parent = session.get( Parent.class, parentId );
243+
parent.addChild( c1 );
244+
```
245+
Instead, c1 must first be re-associated with the Session using merge:
246+
247+
```
248+
Parent parent = session.get( Parent.class, parentId );
249+
Child merged = session.merge( c1 );
250+
parent.addChild( merged );
251+
```
247252

248253
[[todo]]
249254
== Todos (dev)

0 commit comments

Comments
 (0)