Remove us of @SelectBeforeUpdate from tests
This commit is contained in:
parent
83a226c503
commit
e3344e0068
|
@ -22,7 +22,6 @@ import org.hibernate.annotations.OptimisticLockType;
|
||||||
import org.hibernate.annotations.OptimisticLocking;
|
import org.hibernate.annotations.OptimisticLocking;
|
||||||
import org.hibernate.annotations.ParamDef;
|
import org.hibernate.annotations.ParamDef;
|
||||||
import org.hibernate.annotations.SQLRestriction;
|
import org.hibernate.annotations.SQLRestriction;
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
|
|
||||||
import jakarta.persistence.Convert;
|
import jakarta.persistence.Convert;
|
||||||
import jakarta.persistence.ElementCollection;
|
import jakarta.persistence.ElementCollection;
|
||||||
|
@ -40,7 +39,6 @@ import jakarta.persistence.Table;
|
||||||
*/
|
*/
|
||||||
@Entity
|
@Entity
|
||||||
@BatchSize(size = 5)
|
@BatchSize(size = 5)
|
||||||
@SelectBeforeUpdate
|
|
||||||
@DynamicInsert @DynamicUpdate
|
@DynamicInsert @DynamicUpdate
|
||||||
@OptimisticLocking(type = OptimisticLockType.ALL)
|
@OptimisticLocking(type = OptimisticLockType.ALL)
|
||||||
@SQLRestriction("1=1")
|
@SQLRestriction("1=1")
|
||||||
|
|
|
@ -1,324 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.annotations.selectbeforeupdate;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.ElementCollection;
|
|
||||||
import jakarta.persistence.Embeddable;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
import jakarta.persistence.Table;
|
|
||||||
import jakarta.persistence.Version;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Chris Cranford
|
|
||||||
*/
|
|
||||||
@DomainModel(
|
|
||||||
annotatedClasses = {
|
|
||||||
MergeDetachedTest.Foo.class,
|
|
||||||
MergeDetachedTest.Bar.class
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@SessionFactory
|
|
||||||
public class MergeDetachedTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey("HHH-5908")
|
|
||||||
public void testUpdateDetachedUnchanged(SessionFactoryScope scope) {
|
|
||||||
final Bar bar = new Bar( 1, "Bar" );
|
|
||||||
final Foo foo = new Foo( 1, "Foo", bar );
|
|
||||||
|
|
||||||
// this should generate versions
|
|
||||||
scope.inTransaction( session -> {
|
|
||||||
session.persist( bar );
|
|
||||||
session.persist( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// this shouldn't generate a new version.
|
|
||||||
Foo merged = scope.fromTransaction( session ->
|
|
||||||
session.merge( foo )
|
|
||||||
);
|
|
||||||
|
|
||||||
assertThat( bar.getVersion() ).isEqualTo( 0 );
|
|
||||||
assertThat( merged.getVersion() ).isEqualTo( 0 );
|
|
||||||
|
|
||||||
// this should generate a new version
|
|
||||||
Foo merged2 = scope.fromTransaction( session -> {
|
|
||||||
merged.setName( "FooChanged" );
|
|
||||||
return session.merge( merged );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( bar.getVersion() ).isEqualTo( 0 );
|
|
||||||
assertThat( merged2.getVersion() ).isEqualTo( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey("HHH-5908")
|
|
||||||
public void testUpdateDetachedChanged(SessionFactoryScope scope) {
|
|
||||||
final Bar bar = new Bar( 2, "Bar" );
|
|
||||||
final Foo foo = new Foo( 2, "Foo", bar );
|
|
||||||
|
|
||||||
// this should generate versions
|
|
||||||
scope.inTransaction( session -> {
|
|
||||||
session.persist( bar );
|
|
||||||
session.persist( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// this should generate a new version
|
|
||||||
Foo merged = scope.fromTransaction( session -> {
|
|
||||||
foo.setName( "FooChanged" );
|
|
||||||
return session.merge( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( bar.getVersion() ).isEqualTo( 0 );
|
|
||||||
assertThat( merged.getVersion() ).isEqualTo( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey("HHH-5908")
|
|
||||||
public void testUpdateDetachedUnchangedAndChanged(SessionFactoryScope scope) {
|
|
||||||
final Bar bar = new Bar( 3, "Bar" );
|
|
||||||
final Foo foo = new Foo( 3, "Foo", bar );
|
|
||||||
|
|
||||||
// this should generate versions
|
|
||||||
scope.inTransaction( session -> {
|
|
||||||
session.persist( bar );
|
|
||||||
session.persist( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// this shouldn't generate a new version.
|
|
||||||
Foo merged = scope.fromTransaction(
|
|
||||||
session ->
|
|
||||||
session.merge( foo )
|
|
||||||
);
|
|
||||||
|
|
||||||
// this should generate a new version
|
|
||||||
Foo merged2 = scope.fromTransaction( session -> {
|
|
||||||
merged.setName( "FooChanged" );
|
|
||||||
return session.merge( merged );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( bar.getVersion() ).isEqualTo( 0 );
|
|
||||||
assertThat( merged2.getVersion() ).isEqualTo( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey("HHH-5908")
|
|
||||||
public void testUpdateDetachedChangedAndUnchanged(SessionFactoryScope scope) {
|
|
||||||
final Bar bar = new Bar( 4, "Bar" );
|
|
||||||
final Foo foo = new Foo( 4, "Foo", bar );
|
|
||||||
|
|
||||||
// this should generate versions
|
|
||||||
scope.inTransaction( session -> {
|
|
||||||
session.persist( bar );
|
|
||||||
session.persist( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// this should generate a new version
|
|
||||||
Foo merged = scope.fromTransaction( session -> {
|
|
||||||
foo.setName( "FooChanged" );
|
|
||||||
return session.merge( foo );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// this shouldn't generate a new version.
|
|
||||||
Foo merged2 = scope.fromTransaction(
|
|
||||||
session ->
|
|
||||||
session.merge( merged )
|
|
||||||
);
|
|
||||||
|
|
||||||
assertThat( bar.getVersion() ).isEqualTo( 0 );
|
|
||||||
assertThat( merged2.getVersion() ).isEqualTo( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey("HHH-14319")
|
|
||||||
public void testUpdateDetachedWithAttachedPersistentSet(SessionFactoryScope scope) {
|
|
||||||
final Bar bar = new Bar( 5, "Bar" );
|
|
||||||
final Set<Comment> comments = new HashSet<>();
|
|
||||||
comments.add( new Comment( "abc", "me" ) );
|
|
||||||
bar.comments = comments;
|
|
||||||
|
|
||||||
// this should generate versions
|
|
||||||
scope.inTransaction( session -> {
|
|
||||||
session.persist( bar );
|
|
||||||
} );
|
|
||||||
|
|
||||||
final Bar loadedBar = scope.fromTransaction( session -> {
|
|
||||||
// We set the comments to the hash set and leave it "dirty"
|
|
||||||
Bar b = session.find( Bar.class, bar.getId() );
|
|
||||||
b.comments = comments;
|
|
||||||
|
|
||||||
// During flushing, the comments HashSet becomes the backing collection of new PersistentSet which replaces the old entry
|
|
||||||
session.flush();
|
|
||||||
|
|
||||||
// Replace the persistent collection with the backing collection in the field
|
|
||||||
b.comments = comments;
|
|
||||||
|
|
||||||
// It's vital that we try merging a detached instance
|
|
||||||
session.detach( b );
|
|
||||||
return session.merge( b );
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertThat( loadedBar.comments.size() ).isEqualTo( 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Foo")
|
|
||||||
@Table(name = "FooSBU")
|
|
||||||
@SelectBeforeUpdate
|
|
||||||
public static class Foo {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
@Version
|
|
||||||
private Integer version;
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(updatable = false)
|
|
||||||
private Bar bar;
|
|
||||||
|
|
||||||
Foo() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Foo(Integer id, String name, Bar bar) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.bar = bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bar getBar() {
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBar(Bar bar) {
|
|
||||||
this.bar = bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(Integer version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Bar")
|
|
||||||
@Table(name = "BarSBU")
|
|
||||||
public static class Bar {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
@Version
|
|
||||||
private Integer version;
|
|
||||||
@ElementCollection
|
|
||||||
private Set<Comment> comments;
|
|
||||||
|
|
||||||
Bar() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Bar(Integer id, String name) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(Integer version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Comment> getComments() {
|
|
||||||
return comments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setComments(Set<Comment> comments) {
|
|
||||||
this.comments = comments;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Embeddable
|
|
||||||
@Table(name = "CommentSBU")
|
|
||||||
public static class Comment {
|
|
||||||
@Column(name = "bar_comment")
|
|
||||||
private String comment;
|
|
||||||
private String author;
|
|
||||||
|
|
||||||
public Comment() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Comment(String comment, String author) {
|
|
||||||
this.comment = comment;
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getComment() {
|
|
||||||
return comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setComment(String comment) {
|
|
||||||
this.comment = comment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthor(String author) {
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,204 +0,0 @@
|
||||||
package org.hibernate.orm.test.annotations.selectbeforeupdate;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.Cascade;
|
|
||||||
import org.hibernate.annotations.CascadeType;
|
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
import org.hibernate.orm.test.legacy.Child;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
import jakarta.persistence.OneToOne;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
|
||||||
|
|
||||||
@DomainModel(
|
|
||||||
annotatedClasses = {
|
|
||||||
SelectBeforeUpdateWithCascadeTest.ChildEntity.class,
|
|
||||||
SelectBeforeUpdateWithCascadeTest.MappedEntity.class,
|
|
||||||
SelectBeforeUpdateWithCascadeTest.ParentEntity.class
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@SessionFactory
|
|
||||||
@JiraKey("HHH-17560")
|
|
||||||
public class SelectBeforeUpdateWithCascadeTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPersist(SessionFactoryScope scope) {
|
|
||||||
|
|
||||||
ChildEntity childEntity = new ChildEntity();
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
childEntity.setAProperty( "property" );
|
|
||||||
childEntity.setNonInsertableProperty( "nonInsertable" );
|
|
||||||
childEntity.setNonUpdatableProperty( "nonUpdatable" );
|
|
||||||
|
|
||||||
session.persist( childEntity );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
ParentEntity parent1 = new ParentEntity();
|
|
||||||
parent1.setChildEntity( session.merge( childEntity ) );
|
|
||||||
|
|
||||||
session.persist( parent1 );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
ParentEntity parent2 = new ParentEntity();
|
|
||||||
parent2.setChildEntity( session.merge( childEntity ) );
|
|
||||||
|
|
||||||
session.persist( parent2 );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
session -> {
|
|
||||||
List<ChildEntity> children = session.createQuery( "select c from ChildEntity c" ).list();
|
|
||||||
assertThat(children.size()).isEqualTo( 1 );
|
|
||||||
|
|
||||||
List<ParentEntity> parents = session.createQuery( "select p from ParentEntity p" ).list();
|
|
||||||
assertThat(parents.size()).isEqualTo( 2 );
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "ChildEntity")
|
|
||||||
@SelectBeforeUpdate
|
|
||||||
public static class ChildEntity {
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String aProperty;
|
|
||||||
|
|
||||||
@Column(updatable = false)
|
|
||||||
private String nonUpdatableProperty;
|
|
||||||
|
|
||||||
@Column(insertable = false)
|
|
||||||
private String nonInsertableProperty;
|
|
||||||
|
|
||||||
@OneToOne(mappedBy = "childEntity")
|
|
||||||
private MappedEntity mappedEntity;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAProperty() {
|
|
||||||
return aProperty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAProperty(String property) {
|
|
||||||
this.aProperty = property;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MappedEntity getMappedEntity() {
|
|
||||||
return mappedEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMappedEntity(MappedEntity mappedEntity) {
|
|
||||||
this.mappedEntity = mappedEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNonUpdatableProperty() {
|
|
||||||
return nonUpdatableProperty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNonUpdatableProperty(String nonUpdatableProperty) {
|
|
||||||
this.nonUpdatableProperty = nonUpdatableProperty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNonInsertableProperty() {
|
|
||||||
return nonInsertableProperty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNonInsertableProperty(String nonInsertableProperty) {
|
|
||||||
this.nonInsertableProperty = nonInsertableProperty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "MappedEntity")
|
|
||||||
public static class MappedEntity {
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@OneToOne
|
|
||||||
@JoinColumn(name = "child_entity_id", updatable = false)
|
|
||||||
private ChildEntity childEntity;
|
|
||||||
|
|
||||||
private String property;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChildEntity getChildEntity() {
|
|
||||||
return childEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChildEntity(ChildEntity childEntity) {
|
|
||||||
this.childEntity = childEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProperty() {
|
|
||||||
return property;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProperty(String property) {
|
|
||||||
this.property = property;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "ParentEntity")
|
|
||||||
public static class ParentEntity {
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@Cascade({ CascadeType.MERGE, CascadeType.PERSIST})
|
|
||||||
@JoinColumn(name = "child_entity_id")
|
|
||||||
private ChildEntity childEntity;
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChildEntity getChildEntity() {
|
|
||||||
return childEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChildEntity(ChildEntity childEntity) {
|
|
||||||
this.childEntity = childEntity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,253 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.component.empty;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import jakarta.persistence.Embeddable;
|
|
||||||
import jakarta.persistence.Embedded;
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.Version;
|
|
||||||
|
|
||||||
import org.hibernate.EmptyInterceptor;
|
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.type.Type;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
|
||||||
import org.hibernate.testing.transaction.TransactionUtil;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Chris Cranford
|
|
||||||
*/
|
|
||||||
public class SelectBeforeUpdateEmbeddedTest extends BaseCoreFunctionalTestCase {
|
|
||||||
private final OnFlushDirtyInterceptor i = new OnFlushDirtyInterceptor();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] { Person.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void configure(Configuration configuration) {
|
|
||||||
super.configure( configuration );
|
|
||||||
// applies the OnFlushDirtyInterceptor that is meant to track whether a Flush event fires
|
|
||||||
// in situations where it ultimately shouldn't because null composites should equate an
|
|
||||||
// instantiated component with all null properties.
|
|
||||||
configuration.setInterceptor( i );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@TestForIssue(jiraKey = "HHH-11237")
|
|
||||||
public void testSelectBeforeUpdateUsingNullComposites() {
|
|
||||||
// Legacy behavior test
|
|
||||||
testSelectBeforeUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs various tests both available attached and detached entities which use
|
|
||||||
* the {@code @SelectBeforeUpdate} annotation with an {@code @Embedded} component.
|
|
||||||
*/
|
|
||||||
private void testSelectBeforeUpdate() {
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
final Person john = new Person( 1, "John", new Address() );
|
|
||||||
session.persist( john );
|
|
||||||
|
|
||||||
final Person mary = new Person( 2, "Mary", null );
|
|
||||||
session.persist( mary );
|
|
||||||
} );
|
|
||||||
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
final Person john = session.find( Person.class, 1 );
|
|
||||||
i.reset();
|
|
||||||
john.setAddress( null );
|
|
||||||
session.flush();
|
|
||||||
assertEquals( 0, i.getCalls() );
|
|
||||||
|
|
||||||
i.reset();
|
|
||||||
final Person mary = session.find( Person.class, 2 );
|
|
||||||
mary.setAddress( new Address() );
|
|
||||||
session.flush();
|
|
||||||
assertEquals( 0, i.getCalls() );
|
|
||||||
} );
|
|
||||||
|
|
||||||
final Person john = TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
return session.get( Person.class, 1 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
final Person mary = TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
return session.get( Person.class, 2 );
|
|
||||||
} );
|
|
||||||
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
i.reset();
|
|
||||||
john.setAddress( null );
|
|
||||||
session.merge( john );
|
|
||||||
session.flush();
|
|
||||||
assertEquals( 0, i.getCalls() );
|
|
||||||
|
|
||||||
i.reset();
|
|
||||||
mary.setAddress( new Address() );
|
|
||||||
session.merge( mary );
|
|
||||||
session.flush();
|
|
||||||
assertEquals( 0, i.getCalls() );
|
|
||||||
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Person")
|
|
||||||
@SelectBeforeUpdate
|
|
||||||
public static class Person {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
@Embedded
|
|
||||||
private Address address;
|
|
||||||
@Version
|
|
||||||
private Integer version;
|
|
||||||
|
|
||||||
Person() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Person(Integer id, String name, Address address) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddress(Address address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getVersion() {
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(Integer version) {
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Embeddable
|
|
||||||
public static class Address implements Serializable {
|
|
||||||
private String postalCode;
|
|
||||||
private String state;
|
|
||||||
private String address;
|
|
||||||
|
|
||||||
Address() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Address(String postalCode, String state, String address) {
|
|
||||||
this.postalCode = postalCode;
|
|
||||||
this.state = state;
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPostalCode() {
|
|
||||||
return postalCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPostalCode(String postalCode) {
|
|
||||||
this.postalCode = postalCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setState(String state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddress(String address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if ( this == o ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ( o == null || getClass() != o.getClass() ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Address address1 = (Address) o;
|
|
||||||
|
|
||||||
if ( getPostalCode() != null ? !getPostalCode().equals( address1.getPostalCode() ) : address1.getPostalCode() != null ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ( getState() != null ? !getState().equals( address1.getState() ) : address1.getState() != null ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return getAddress() != null ? getAddress().equals( address1.getAddress() ) : address1.getAddress() == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = getPostalCode() != null ? getPostalCode().hashCode() : 0;
|
|
||||||
result = 31 * result + ( getState() != null ? getState().hashCode() : 0 );
|
|
||||||
result = 31 * result + ( getAddress() != null ? getAddress().hashCode() : 0 );
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class OnFlushDirtyInterceptor extends EmptyInterceptor {
|
|
||||||
private AtomicInteger calls = new AtomicInteger();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onFlushDirty(Object entity,
|
|
||||||
Serializable id,
|
|
||||||
Object[] currentState,
|
|
||||||
Object[] previousState,
|
|
||||||
String[] propertyNames,
|
|
||||||
Type[] types) {
|
|
||||||
calls.incrementAndGet();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCalls() {
|
|
||||||
return calls.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset() {
|
|
||||||
calls.set( 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.orm.test.write;
|
||||||
import org.hibernate.annotations.DynamicUpdate;
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
import org.hibernate.annotations.OptimisticLockType;
|
import org.hibernate.annotations.OptimisticLockType;
|
||||||
import org.hibernate.annotations.OptimisticLocking;
|
import org.hibernate.annotations.OptimisticLocking;
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
|
||||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||||
|
@ -319,7 +318,6 @@ public class DynamicUpdateTests {
|
||||||
@Entity( name = "AttachableJob" )
|
@Entity( name = "AttachableJob" )
|
||||||
@Table( name = "AttachableJob" )
|
@Table( name = "AttachableJob" )
|
||||||
@DynamicUpdate
|
@DynamicUpdate
|
||||||
@SelectBeforeUpdate
|
|
||||||
public static class AttachableJob {
|
public static class AttachableJob {
|
||||||
@Id
|
@Id
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
|
@ -1,222 +0,0 @@
|
||||||
/*
|
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
|
||||||
*
|
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
|
||||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.envers.integration.update;
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.JoinColumn;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
|
|
||||||
import org.hibernate.annotations.SelectBeforeUpdate;
|
|
||||||
import org.hibernate.envers.Audited;
|
|
||||||
import org.hibernate.orm.test.envers.BaseEnversFunctionalTestCase;
|
|
||||||
import org.hibernate.orm.test.envers.Priority;
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.transaction.TransactionUtil;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Chris Cranford
|
|
||||||
*/
|
|
||||||
@JiraKey("HHH-11056")
|
|
||||||
public class SelectBeforeUpdateTest extends BaseEnversFunctionalTestCase {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] { Book.class, Author.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Priority(10)
|
|
||||||
public void initDataUpdateDetachedUnchanged() {
|
|
||||||
final Author author = new Author( 1, "Author1" );
|
|
||||||
final Book book = new Book( 1, "Book1", author );
|
|
||||||
|
|
||||||
// Revision 1 - insert new entities.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.persist( author );
|
|
||||||
session.persist( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 2 - update detached with no changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Priority(9)
|
|
||||||
public void initDataUpdateDetachedChanged() {
|
|
||||||
final Author author = new Author( 2, "Author2" );
|
|
||||||
final Book book = new Book( 2, "Book2", author );
|
|
||||||
|
|
||||||
// Revision 1 - insert new entities.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.persist( author );
|
|
||||||
session.persist( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 2 - update detached with changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
book.setName( "Book2Updated" );
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Priority(8)
|
|
||||||
public void initDataUpdateDetachedUnchangedAndChanged() {
|
|
||||||
final Author author = new Author( 3, "Author3" );
|
|
||||||
final Book book = new Book( 3, "Book3", author );
|
|
||||||
|
|
||||||
// Revision 1 - insert new entities.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.persist( author );
|
|
||||||
session.persist( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 2 - update detached with no changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 3 - update detached with changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
book.setName( "Book3Updated" );
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Priority(7)
|
|
||||||
public void initDataUpdateDetachedChangedAndUnchanged() {
|
|
||||||
final Author author = new Author( 4, "Author4" );
|
|
||||||
final Book book = new Book( 4, "Book4", author );
|
|
||||||
|
|
||||||
// Revision 1 - insert new entities.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.persist( author );
|
|
||||||
session.persist( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 2 - update detached with changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
book.setName( "Book4Updated" );
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// Revision 3 - update detached with no changes.
|
|
||||||
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
|
||||||
session.merge( book );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRevisionCountsUpdateDetachedUnchanged() {
|
|
||||||
assertEquals( 1, getAuditReader().getRevisions( Author.class, 1 ).size() );
|
|
||||||
assertEquals( 1, getAuditReader().getRevisions( Book.class, 1 ).size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRevisionCountsUpdateDetachedChanged() {
|
|
||||||
assertEquals( 1, getAuditReader().getRevisions( Author.class, 2 ).size() );
|
|
||||||
assertEquals( 2, getAuditReader().getRevisions( Book.class, 2 ).size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRevisionCountsUpdateDetachedUnchangedAndChanged() {
|
|
||||||
assertEquals( 1, getAuditReader().getRevisions( Author.class, 3 ).size() );
|
|
||||||
assertEquals( 2, getAuditReader().getRevisions( Book.class, 3 ).size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRevisionCountsUpdateDetachedChangedAndUnchanged() {
|
|
||||||
assertEquals( 1, getAuditReader().getRevisions( Author.class, 4 ).size() );
|
|
||||||
assertEquals( 2, getAuditReader().getRevisions( Book.class, 4 ).size() );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Book")
|
|
||||||
@SelectBeforeUpdate
|
|
||||||
@Audited
|
|
||||||
public static class Book {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(updatable = false)
|
|
||||||
private Author author;
|
|
||||||
|
|
||||||
Book() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Book(Integer id, String name, Author author) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Author getAuthor() {
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthor(Author author) {
|
|
||||||
this.author = author;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Author")
|
|
||||||
@Audited
|
|
||||||
public static class Author {
|
|
||||||
@Id
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
Author() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Author(Integer id, String name) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue