HHH-13590 : test cases
This commit is contained in:
parent
ea301a7084
commit
11409ed633
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* 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.test.cascade;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-13590")
|
||||
public class CascadeMergeToProxyEntityCopyAllowedTest extends BaseCoreFunctionalTestCase {
|
||||
private Project defaultProject;
|
||||
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
AbstractEntity.class,
|
||||
Event.class,
|
||||
Project.class,
|
||||
Speaker.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
final Event root = (Event) persistEntity( new Event( null, defaultProject ) );
|
||||
|
||||
Event rootFromDB = doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
TypedQuery<Event> eventTypedQuery = session.createQuery(
|
||||
"SELECT e FROM Event e LEFT JOIN FETCH e.speakers LEFT JOIN FETCH e.children LEFT JOIN FETCH e.project WHERE e.objectID = :oid",
|
||||
Event.class
|
||||
);
|
||||
|
||||
eventTypedQuery.setParameter( "oid", root.getObjectID() );
|
||||
|
||||
return eventTypedQuery.getSingleResult();
|
||||
|
||||
}
|
||||
);
|
||||
assertNotNull( rootFromDB );
|
||||
assertEquals(0, rootFromDB.getChildren().size());
|
||||
assertEquals( 0, rootFromDB.getSpeakers().size() );
|
||||
assertEquals( root, rootFromDB );
|
||||
|
||||
Speaker speaker = (Speaker) persistEntity( new Speaker(defaultProject) );
|
||||
final long speakerId = speaker.getObjectID();
|
||||
|
||||
speaker = doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return session.find( Speaker.class, speakerId );
|
||||
}
|
||||
);
|
||||
assertNotNull( speaker );
|
||||
|
||||
Event child = new Event(rootFromDB, defaultProject);
|
||||
child.addSpeaker( speaker );
|
||||
|
||||
rootFromDB = (Event) persistEntity( rootFromDB );
|
||||
final long rootFromDBId = rootFromDB.getObjectID();
|
||||
rootFromDB = doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
TypedQuery<Event> eventTypedQuery = session.createQuery(
|
||||
"SELECT e FROM Event e LEFT JOIN FETCH e.speakers LEFT JOIN FETCH e.children LEFT JOIN FETCH e.project WHERE e.objectID = :oid",
|
||||
Event.class
|
||||
);
|
||||
|
||||
eventTypedQuery.setParameter( "oid", rootFromDBId );
|
||||
|
||||
return eventTypedQuery.getSingleResult();
|
||||
|
||||
}
|
||||
);
|
||||
assertNotNull( rootFromDB );
|
||||
assertEquals(1, rootFromDB.getChildren().size());
|
||||
assertEquals(0, rootFromDB.getSpeakers().size());
|
||||
|
||||
}
|
||||
|
||||
private Object persistEntity(Object entity ) {
|
||||
return doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
Object mergedEntity = session.merge( entity );
|
||||
session.persist( mergedEntity );
|
||||
session.flush();
|
||||
return mergedEntity;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( AvailableSettings.MERGE_ENTITY_COPY_OBSERVER, "allow" );
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupData() {
|
||||
Long objectId = doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
Project project = (Project) session.merge( new Project() );
|
||||
session.persist( project );
|
||||
session.flush();
|
||||
return project.getObjectID();
|
||||
}
|
||||
);
|
||||
doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
TypedQuery<Project> projectTypedQuery = session.createQuery("SELECT p FROM Project p WHERE p.objectID = :oid", Project.class);
|
||||
|
||||
projectTypedQuery.setParameter("oid", objectId);
|
||||
|
||||
defaultProject = projectTypedQuery.getSingleResult();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public static class AbstractEntity {
|
||||
|
||||
static long INVALID_OBJECT_ID = -1 ;
|
||||
|
||||
@Transient
|
||||
protected static final Random RANDOM_GENERATOR = new Random();
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Column(name = "id")
|
||||
protected Long objectID = INVALID_OBJECT_ID;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 36)
|
||||
private final String bID;
|
||||
|
||||
protected AbstractEntity() {
|
||||
bID = UUID.nameUUIDFromBytes(
|
||||
( Long.toString( System.currentTimeMillis() ) + RANDOM_GENERATOR.nextInt() )
|
||||
.getBytes()
|
||||
).toString();
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public long getObjectID() {
|
||||
return objectID;
|
||||
}
|
||||
|
||||
public static boolean isValidObjectID(long id) {
|
||||
return (id > 0 && id != AbstractEntity.INVALID_OBJECT_ID);
|
||||
}
|
||||
|
||||
public boolean isPersistent() {
|
||||
return isValidObjectID(getObjectID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[id=%d]", getClass().getSimpleName(), getObjectID());
|
||||
}
|
||||
|
||||
public String getBID() {
|
||||
return bID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AbstractEntity that = (AbstractEntity) o;
|
||||
|
||||
return bID != null ? bID.equals(that.bID) : that.bID == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return bID != null ? bID.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Event")
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public static class Event extends AbstractEntity {
|
||||
|
||||
@ManyToOne(targetEntity = Event.class, fetch = FetchType.EAGER)
|
||||
private Event parent;
|
||||
|
||||
@OneToMany(targetEntity = Event.class, cascade = { CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "parent")
|
||||
private Set<Event> children = new HashSet<>();
|
||||
|
||||
@ManyToOne(targetEntity = Project.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
|
||||
private Project project;
|
||||
|
||||
@ManyToMany(targetEntity = Speaker.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REFRESH})
|
||||
private Set<Speaker> speakers = new HashSet<>();
|
||||
|
||||
|
||||
public Event() {
|
||||
//framework purpose
|
||||
}
|
||||
|
||||
public Event(Event parent, Project project) {
|
||||
setParent(parent);
|
||||
setProject(project);
|
||||
|
||||
if (parent == null) {
|
||||
//nothing to do here, Event has no parent
|
||||
} else {
|
||||
parent.addChild(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setParent(Event parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void setProject(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public Event getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public Set<Speaker> getSpeakers() {
|
||||
return Collections.unmodifiableSet( speakers );
|
||||
}
|
||||
|
||||
public Set<Event> getChildren() {
|
||||
return Collections.unmodifiableSet( children );
|
||||
}
|
||||
|
||||
public void addSpeaker(Speaker speaker) {
|
||||
assert speaker != null;
|
||||
this.speakers.add(speaker);
|
||||
}
|
||||
|
||||
public void addChild(Event event) {
|
||||
assert event != null;
|
||||
this.children.add(event);
|
||||
event.setParent(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Project")
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public static class Project extends AbstractEntity {
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Speaker")
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public static class Speaker extends AbstractEntity {
|
||||
|
||||
|
||||
@ManyToOne(targetEntity = Project.class, fetch = FetchType.LAZY,
|
||||
cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
|
||||
private Project project;
|
||||
|
||||
public Speaker() {
|
||||
|
||||
}
|
||||
|
||||
public Speaker(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.test.cascade;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@TestForIssue( jiraKey = "HHH-13590")
|
||||
public class CascadeMergeToProxySimpleTest extends BaseCoreFunctionalTestCase {
|
||||
protected static final Random RANDOM_GENERATOR = new Random();
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
AbstractEntity.class,
|
||||
Event.class,
|
||||
Project.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
final Event root = (Event) mergeEntity( new Event( generateBId(), new Project( generateBId() ) ) );
|
||||
Event rootFromDB = (Event) mergeEntity( root );
|
||||
|
||||
assertNotNull( rootFromDB );
|
||||
}
|
||||
|
||||
private Object mergeEntity(Object entity) {
|
||||
return doInHibernate(
|
||||
this::sessionFactory, session -> {
|
||||
return session.merge( entity );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private String generateBId() {
|
||||
return UUID.nameUUIDFromBytes(
|
||||
( Long.toString( System.currentTimeMillis() ) + RANDOM_GENERATOR.nextInt() )
|
||||
.getBytes()
|
||||
).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public static class AbstractEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Column(name = "id")
|
||||
protected Long objectID;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 36)
|
||||
private String bID;
|
||||
|
||||
protected AbstractEntity() {
|
||||
}
|
||||
|
||||
protected AbstractEntity(String bId) {
|
||||
this.bID = bId;
|
||||
}
|
||||
public long getObjectID() {
|
||||
return objectID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s[id=%d]", getClass().getSimpleName(), getObjectID());
|
||||
}
|
||||
|
||||
public String getBID() {
|
||||
return bID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if ( o == null || !this.getClass().isInstance( o ) ) return false;
|
||||
|
||||
AbstractEntity that = (AbstractEntity) o;
|
||||
|
||||
return bID != null ? bID.equals( that.bID) : that.bID == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return bID != null ? bID.hashCode() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Event")
|
||||
public static class Event extends AbstractEntity {
|
||||
|
||||
@OneToMany(targetEntity = Event.class, cascade = { CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
private Set<Event> children = new HashSet<>();
|
||||
|
||||
@ManyToOne(targetEntity = Project.class, fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
|
||||
private Project project;
|
||||
|
||||
public Event() {
|
||||
//framework purpose
|
||||
}
|
||||
|
||||
public Event(String bid, Project project) {
|
||||
super( bid );
|
||||
setProject(project);
|
||||
}
|
||||
|
||||
public void setProject(Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public Set<Event> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void addChild(Event event) {
|
||||
assert event != null;
|
||||
this.children.add(event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Project")
|
||||
public static class Project extends AbstractEntity {
|
||||
|
||||
Project() {
|
||||
}
|
||||
|
||||
Project(String bId) {
|
||||
super( bId );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue