diff --git a/migration-guide.adoc b/migration-guide.adoc index 4b7bfa7610..934c47ba23 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -41,7 +41,7 @@ For many years Hibernate has used the Hibernate Commons Annotations (HCANN) libr related to understanding the structure of an application domain model, reading annotations and weaving in XML mapping documents. -However, HCANN suffers from a number of limitations that continue to be problematic. And given +However, HCANN suffers from a number of limitations that continued to be problematic. And given the use of HCANN across multiple projects, doing the needed refactoring was simply not possible. The https://github.com/hibernate/hibernate-models[Hibernate Models] project was developed to be a better alternative @@ -50,16 +50,16 @@ annotations. Check out its project page for complete details. 7.0 uses Hibernate Models in place of HCANN. -NOTE: Currently, the `hibernate-envers` module still uses HCANN. That will change during continued 7.0 development. +NOTE: Currently, the `hibernate-envers` module still uses HCANN. That will change during continued 7.x development. -[[annotation-validation]] -== Annotation Validations +[[model-validation]] +== Domain Model Validations 7.0 adds many more checks about illegal use of annotations. - +[[PersistentAttributeType]] === PersistentAttributeType As of 7.0, Hibernate applies much better validation of an attribute specifying multiple PersistentAttributeTypes. @@ -100,11 +100,76 @@ class Book { // previously ignored, this is an error now @Column(name="category") String getType() { ... } - - ... } ---- +[[java-beans]] +=== JavaBean Conventions + +Previous versions allowed some questionable (at best) attribute naming patterns. These are no longer supported. E.g. + +[source,java] +---- +@Basic +String isDefault(); +---- + + + +[[flush-persist]] +== Session flush and persist + +The removal of `CascadeType.SAVE_UPDATE` slightly changes the persist and flush behaviour to conform with Jakarta Persistence. + +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 Session. + +To re-associate the detached entity with the Session the `Session#merge` method can be used. + +Consider the following model + +[source,java] +---- +@Entity +class Parent { + ... + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true) + @LazyCollection(value = LazyCollectionOption.EXTRA) + private Set children = new HashSet<>(); + + public void addChild(Child child) { + children.add( child ); + child.setParent( this ); + } +} + +@Entity +class Child { + ... + + @ManyToOne + private Parent parent; +} +---- + +Assuming we have `c1` as a detached `Child`, the following code will now result in `jakarta.persistence.EntityExistsException` being thrown at flush time: + +[source,java] +---- +Parent parent = session.get( Parent.class, parentId ); +parent.addChild( c1 ); +---- + +Instead, `c1` must first be re-associated with the Session using merge: + + +[source,java] +---- +Parent parent = session.get( Parent.class, parentId ); +Child merged = session.merge( c1 ); +parent.addChild( merged ); +---- + [[auto-cascade-persist]] == Cascading persistence for `@Id` and `@MapsId` fields @@ -123,36 +188,6 @@ as part of schema generation. 7.0 adds the same capability for enums mapped usi by asking the converter to convert all the enum constants on start up. -[[java-beans]] -== JavaBean Conventions - -Previous versions allowed some questionable (at best) attribute naming patterns. These are no longer supported. E.g. - -[source,java] ----- -@Basic -String isDefault(); ----- - - - -[[cleanup]] -== Some Cleanup - -* Removed `SqmQualifiedJoin`. All joins are qualified. -* Removed `AdditionalJaxbMappingProducer`, deprecated in favor of `AdditionalMappingContributor` -* Removed `MetadataContributor`, deprecated in favor of `AdditionalMappingContributor` -* Removed `@Persister`. -* Removed `hibernate.mapping.precedence` and friends -* Removed `org.hibernate.Session#save(Object object)` and `org.hibernate.Session#save(String entityName, Object object)` in favor of `org.hibernate.Session#persist(Object object)` and `org.hibernate.Session#persist(String entityName, Object object)` -* Removed `org.hibernate.Session#saveOrUpdate(Object object)` and `org.hibernate.Session#saveOrUpdate(String entityName, Object object)` in favor `persist` if the entity is transient or `merge` if the entity is detached. -* Removed `org.hibernate.Session#update(Object object` and `org.hibernate.Session#update(String entityName, Object object)` in favor of `org.hibernate.Session.merge(T object)` and `org.hibernate.Session.merge(String entityName, T object)` -* Removed `org.hibernate.annotations.CascadeType.SAVE_UPDATE` in favor of `org.hibernate.annotations.CascadeType.PERSIST` + `org.hibernate.annotations.CascadeType.MERGE` -* Removed `@SelectBeforeUpdate` -* Removed `org.hibernate.Session#delete(Object object)` and `org.hibernate.Session#delete(String entityName, Object object)` in favor of `org.hibernate.Session#remove(Object object)` -* Removed `org.hibernate.annotations.CascadeType.DELETE` in favor of `org.hibernate.annotations.CascadeType#REMOVE` -* Removed the attribute value from `@DynamicInsert` and `@DynamicUpdate` - [[ddl-implicit-datatype-timestamp]] == Default precision for timestamp on some databases @@ -194,61 +229,24 @@ one file at a time. This is now done across the entire set of `hbm.xml` files a While most users will never see this change, it might impact integrations which tie-in to XML processing. -[[flush-persist]] -== Session flush and persist -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. +[[cleanup]] +== Cleanup -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. +* Removed `SqmQualifiedJoin`. All joins are qualified. +* Removed `AdditionalJaxbMappingProducer`, deprecated in favor of `AdditionalMappingContributor` +* Removed `MetadataContributor`, deprecated in favor of `AdditionalMappingContributor` +* Removed `@Persister`. +* Removed `hibernate.mapping.precedence` and friends +* Removed `org.hibernate.Session#save` in favor of `org.hibernate.Session#persist` +* Removed `org.hibernate.Session#saveOrUpdate` in favor `#persist` if the entity is transient or `#merge` if the entity is detached. +* Removed `org.hibernate.Session#update` in favor of `org.hibernate.Session.merge` +* Removed `org.hibernate.annotations.CascadeType.SAVE_UPDATE` in favor of `org.hibernate.annotations.CascadeType.PERSIST` + `org.hibernate.annotations.CascadeType.MERGE` +* Removed `@SelectBeforeUpdate` +* Removed `org.hibernate.Session#delete` in favor of `org.hibernate.Session#remove` +* Removed `org.hibernate.annotations.CascadeType.DELETE` in favor of `org.hibernate.annotations.CascadeType#REMOVE` +* Removed the attribute value from `@DynamicInsert` and `@DynamicUpdate` -To re-associate the detached entity with the Session the `Session#merge` method can be used. - -Consider the following model - -``` -@Entity -class Parent { - - ... - - @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true) - @LazyCollection(value = LazyCollectionOption.EXTRA) - private Set children = new HashSet<>(); - - public void addChild(Child child) { - children.add( child ); - child.setParent( this ); - } -} - -@Entity -class Child { - - ... - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @ManyToOne - private Parent parent; -} - -``` - -Assuming we have c1 as a detached Child, the following code will now result in jakarta.persistence.EntityExistsException being thrown at flush time: - -``` -Parent parent = session.get( Parent.class, parentId ); -parent.addChild( c1 ); -``` -Instead, c1 must first be re-associated with the Session using merge: - -``` -Parent parent = session.get( Parent.class, parentId ); -Child merged = session.merge( c1 ); -parent.addChild( merged ); -``` [[todo]] == Todos (dev)