HHH-14103 : Add test cases showing that an entity's transient attribute can be overridden to be persistent in entity subclasses

(cherry picked from commit fb40f8edc0)
This commit is contained in:
Gail Badner 2020-07-21 17:30:42 -07:00 committed by gbadner
parent 7317331108
commit d7400b5a08
4 changed files with 1514 additions and 0 deletions

View File

@ -0,0 +1,380 @@
/*
* 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.inheritance;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.testing.FailureExpected;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
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;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@TestForIssue(jiraKey = "HHH-14103")
public class TransientOverrideAsPersistentJoined extends BaseNonConfigCoreFunctionalTestCase {
@Test
public void testFindByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.find( Employee.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Employee writer = session.find( Employee.class, "John Smith" );
assertTrue( Writer.class.isInstance( writer ) );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( ( (Writer) writer ).getGroup() );
final Group group = ( (Writer) writer ).getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testFindBySubclass() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.find( Editor.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = session.find( Writer.class, "John Smith" );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testQueryByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final List<Employee> employees = session.createQuery( "from Employee", Employee.class )
.getResultList();
assertEquals( 2, employees.size() );
assertTrue( Editor.class.isInstance( employees.get( 0 ) ) );
assertTrue( Writer.class.isInstance( employees.get( 1 ) ) );
final Editor editor = (Editor) employees.get( 0 );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = (Writer) employees.get( 1 );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
});
}
@Test
@FailureExpected( jiraKey = "HHH-12981")
public void testQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
@FailureExpected( jiraKey = "HHH-12981")
public void testQueryByRootClassAndOverridenPropertyTreat() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee e where treat( e as Editor ).title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee e where treat( e as Writer).title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryBySublassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.createQuery( "from Editor where title=:title", Editor.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Writer writer = session.createQuery( "from Writer where title=:title", Writer.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertNotNull( writer.getGroup() );
assertEquals( writer.getTitle(), writer.getGroup().getName() );
});
}
@Test
@FailureExpected( jiraKey = "HHH-12981")
public void testCriteriaQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final CriteriaBuilder builder = session.getCriteriaBuilder();
final CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
final Root<Employee> root = query.from( Employee.class );
final ParameterExpression<String> parameter = builder.parameter( String.class, "title" );
final Predicate predicateEditor = builder.equal(
builder.treat( root, Editor.class ).get( "title" ),
parameter
);
query.where( predicateEditor );
final Employee editor = session.createQuery( query )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Predicate predicateWriter = builder.equal(
builder.treat( root, Writer.class ).get( "title" ),
parameter
);
query.where( predicateWriter );
final Employee writer = session.createQuery( query )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Before
public void setupData() {
doInHibernate( this::sessionFactory, session -> {
Job jobEditor = new Job("Edit");
jobEditor.setEmployee(new Editor("Jane Smith", "Senior Editor"));
Job jobWriter= new Job("Write");
jobWriter.setEmployee(new Writer("John Smith", new Group("Writing")));
Employee editor = jobEditor.getEmployee();
Employee writer = jobWriter.getEmployee();
Group group = Writer.class.cast( writer ).getGroup();
session.persist( editor );
session.persist( group );
session.persist( writer );
session.persist( jobEditor );
session.persist( jobWriter );
});
}
@After
public void cleanupData() {
doInHibernate( this::sessionFactory, session -> {
session.createQuery( "delete from Job" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from Group" ).executeUpdate();
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Employee.class,
Editor.class,
Writer.class,
Group.class,
Job.class
};
}
@Entity(name="Employee")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name="department")
public static abstract class Employee {
private String name;
private String title;
protected Employee(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@Transient
public String getTitle() {
return title;
}
protected Employee() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setTitle(String title) {
this.title = title;
}
}
@Entity(name = "Editor")
public static class Editor extends Employee {
public Editor(String name, String title) {
super(name);
setTitle( title );
}
@Column(name = "e_title")
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Editor() {
// this form used by Hibernate
super();
}
}
@Entity(name = "Writer")
public static class Writer extends Employee {
private Group group;
public Writer(String name, Group group) {
super(name);
setGroup(group);
}
// Cannot have a constraint on e_title because
// Editor#title (which uses the same e_title column) can be non-null,
// and there is no associated group.
@ManyToOne(optional = false)
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
public Group getGroup() {
return group;
}
@Column(name = "e_title", insertable = false, updatable = false)
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Writer() {
// this form used by Hibernate
super();
}
protected void setGroup(Group group) {
this.group = group;
setTitle( group.getName() );
}
}
@Entity(name = "Group")
@Table(name = "WorkGroup")
public static class Group {
private String name;
public Group(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
protected Group() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
}
@Entity(name = "Job")
public static class Job {
private String name;
private Employee employee;
public Job(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@OneToOne
@JoinColumn(name="employee_name")
public Employee getEmployee() {
return employee;
}
protected Job() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setEmployee(Employee e) {
this.employee = e;
}
}
}

View File

@ -0,0 +1,381 @@
/*
* 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.inheritance;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
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;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@TestForIssue(jiraKey = "HHH-14103")
public class TransientOverrideAsPersistentMappedSuperclass extends BaseNonConfigCoreFunctionalTestCase {
@Test
public void testFindByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.find( Employee.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Employee writer = session.find( Employee.class, "John Smith" );
assertTrue( Writer.class.isInstance( writer ) );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( ( (Writer) writer ).getGroup() );
final Group group = ( (Writer) writer ).getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testFindBySubclass() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.find( Editor.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = session.find( Writer.class, "John Smith" );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testQueryByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final List<Employee> employees = session.createQuery( "from Employee", Employee.class )
.getResultList();
assertEquals( 2, employees.size() );
assertTrue( Editor.class.isInstance( employees.get( 0 ) ) );
assertTrue( Writer.class.isInstance( employees.get( 1 ) ) );
final Editor editor = (Editor) employees.get( 0 );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = (Writer) employees.get( 1 );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenPropertyTreat() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee e where treat( e as Editor ).title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee e where treat( e as Writer).title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryBySublassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.createQuery( "from Editor where title=:title", Editor.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Writer writer = session.createQuery( "from Writer where title=:title", Writer.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertNotNull( writer.getGroup() );
assertEquals( writer.getTitle(), writer.getGroup().getName() );
});
}
@Test
public void testCriteriaQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final CriteriaBuilder builder = session.getCriteriaBuilder();
final CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
final Root<Employee> root = query.from( Employee.class );
final ParameterExpression<String> parameter = builder.parameter( String.class, "title" );
final Predicate predicateEditor = builder.equal(
builder.treat( root, Editor.class ).get( "title" ),
parameter
);
query.where( predicateEditor );
final Employee editor = session.createQuery( query )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Predicate predicateWriter = builder.equal(
builder.treat( root, Writer.class ).get( "title" ),
parameter
);
query.where( predicateWriter );
final Employee writer = session.createQuery( query )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Before
public void setupData() {
doInHibernate( this::sessionFactory, session -> {
Job jobEditor = new Job("Edit");
jobEditor.setEmployee(new Editor("Jane Smith", "Senior Editor"));
Job jobWriter= new Job("Write");
jobWriter.setEmployee(new Writer("John Smith", new Group("Writing")));
Employee editor = jobEditor.getEmployee();
Employee writer = jobWriter.getEmployee();
Group group = Writer.class.cast( writer ).getGroup();
session.persist( editor );
session.persist( group );
session.persist( writer );
session.persist( jobEditor );
session.persist( jobWriter );
});
}
@After
public void cleanupData() {
doInHibernate( this::sessionFactory, session -> {
session.createQuery( "delete from Job" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from Group" ).executeUpdate();
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Employee.class,
Editor.class,
Writer.class,
Group.class,
Job.class
};
}
@MappedSuperclass
public static class AbstractEmployee {
private String title;
@Transient
public String getTitle() {
return title;
}
protected void setTitle(String title) {
this.title = title;
}
}
@Entity(name="Employee")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="department")
public static abstract class Employee extends AbstractEmployee {
private String name;
protected Employee(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
protected Employee() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
}
@Entity(name = "Editor")
public static class Editor extends Employee {
public Editor(String name, String title) {
super(name);
setTitle( title );
}
@Column(name = "e_title")
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Editor() {
// this form used by Hibernate
super();
}
}
@Entity(name = "Writer")
public static class Writer extends Employee {
private Group group;
public Writer(String name, Group group) {
super(name);
setGroup(group);
}
// Cannot have a constraint on e_title because
// Editor#title (which uses the same e_title column) can be non-null,
// and there is no associated group.
@ManyToOne(optional = false)
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
public Group getGroup() {
return group;
}
@Column(name = "e_title", insertable = false, updatable = false)
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Writer() {
// this form used by Hibernate
super();
}
protected void setGroup(Group group) {
this.group = group;
setTitle( group.getName() );
}
}
@Entity(name = "Group")
@Table(name = "WorkGroup")
public static class Group {
private String name;
public Group(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
protected Group() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
}
@Entity(name = "Job")
public static class Job {
private String name;
private Employee employee;
public Job(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@OneToOne
@JoinColumn(name="employee_name")
public Employee getEmployee() {
return employee;
}
protected Job() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setEmployee(Employee e) {
this.employee = e;
}
}
}

View File

@ -0,0 +1,377 @@
/*
* 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.inheritance;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
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;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@TestForIssue(jiraKey = "HHH-14103")
public class TransientOverrideAsPersistentSingleTable extends BaseNonConfigCoreFunctionalTestCase {
@Test
public void testFindByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.find( Employee.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Employee writer = session.find( Employee.class, "John Smith" );
assertTrue( Writer.class.isInstance( writer ) );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( ( (Writer) writer ).getGroup() );
final Group group = ( (Writer) writer ).getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testFindBySubclass() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.find( Editor.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = session.find( Writer.class, "John Smith" );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testQueryByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final List<Employee> employees = session.createQuery( "from Employee", Employee.class )
.getResultList();
assertEquals( 2, employees.size() );
assertTrue( Editor.class.isInstance( employees.get( 0 ) ) );
assertTrue( Writer.class.isInstance( employees.get( 1 ) ) );
final Editor editor = (Editor) employees.get( 0 );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = (Writer) employees.get( 1 );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenPropertyTreat() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee e where treat( e as Editor ).title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee e where treat( e as Writer).title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryBySublassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.createQuery( "from Editor where title=:title", Editor.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Writer writer = session.createQuery( "from Writer where title=:title", Writer.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertNotNull( writer.getGroup() );
assertEquals( writer.getTitle(), writer.getGroup().getName() );
});
}
@Test
public void testCriteriaQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final CriteriaBuilder builder = session.getCriteriaBuilder();
final CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
final Root<Employee> root = query.from( Employee.class );
final ParameterExpression<String> parameter = builder.parameter( String.class, "title" );
final Predicate predicateEditor = builder.equal(
builder.treat( root, Editor.class ).get( "title" ),
parameter
);
query.where( predicateEditor );
final Employee editor = session.createQuery( query )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Predicate predicateWriter = builder.equal(
builder.treat( root, Writer.class ).get( "title" ),
parameter
);
query.where( predicateWriter );
final Employee writer = session.createQuery( query )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Before
public void setupData() {
doInHibernate( this::sessionFactory, session -> {
Job jobEditor = new Job("Edit");
jobEditor.setEmployee(new Editor("Jane Smith", "Senior Editor"));
Job jobWriter= new Job("Write");
jobWriter.setEmployee(new Writer("John Smith", new Group("Writing")));
Employee editor = jobEditor.getEmployee();
Employee writer = jobWriter.getEmployee();
Group group = Writer.class.cast( writer ).getGroup();
session.persist( editor );
session.persist( group );
session.persist( writer );
session.persist( jobEditor );
session.persist( jobWriter );
});
}
@After
public void cleanupData() {
doInHibernate( this::sessionFactory, session -> {
session.createQuery( "delete from Job" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from Group" ).executeUpdate();
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Employee.class,
Editor.class,
Writer.class,
Group.class,
Job.class
};
}
@Entity(name="Employee")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="department")
public static abstract class Employee {
private String name;
private String title;
protected Employee(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@Transient
public String getTitle() {
return title;
}
protected Employee() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setTitle(String title) {
this.title = title;
}
}
@Entity(name = "Editor")
public static class Editor extends Employee {
public Editor(String name, String title) {
super(name);
setTitle( title );
}
@Column(name = "e_title")
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Editor() {
// this form used by Hibernate
super();
}
}
@Entity(name = "Writer")
public static class Writer extends Employee {
private Group group;
public Writer(String name, Group group) {
super(name);
setGroup(group);
}
// Cannot have a constraint on e_title because
// Editor#title (which uses the same e_title column) can be non-null,
// and there is no associated group.
@ManyToOne(optional = false)
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
public Group getGroup() {
return group;
}
@Column(name = "e_title", insertable = false, updatable = false)
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Writer() {
// this form used by Hibernate
super();
}
protected void setGroup(Group group) {
this.group = group;
setTitle( group.getName() );
}
}
@Entity(name = "Group")
@Table(name = "WorkGroup")
public static class Group {
private String name;
public Group(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
protected Group() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
}
@Entity(name = "Job")
public static class Job {
private String name;
private Employee employee;
public Job(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@OneToOne
@JoinColumn(name="employee_name")
public Employee getEmployee() {
return employee;
}
protected Job() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setEmployee(Employee e) {
this.employee = e;
}
}
}

View File

@ -0,0 +1,376 @@
/*
* 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.inheritance;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.After;
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;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@TestForIssue(jiraKey = "HHH-14103")
public class TransientOverrideAsPersistentTablePerClass extends BaseNonConfigCoreFunctionalTestCase {
@Test
public void testFindByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.find( Employee.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Employee writer = session.find( Employee.class, "John Smith" );
assertTrue( Writer.class.isInstance( writer ) );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( ( (Writer) writer ).getGroup() );
final Group group = ( (Writer) writer ).getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testFindBySubclass() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.find( Editor.class, "Jane Smith" );
assertNotNull( editor );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = session.find( Writer.class, "John Smith" );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
final Job jobEditor = session.find( Job.class, "Edit" );
assertSame( editor, jobEditor.getEmployee() );
final Job jobWriter = session.find( Job.class, "Write" );
assertSame( writer, jobWriter.getEmployee() );
});
}
@Test
public void testQueryByRootClass() {
doInHibernate( this::sessionFactory, session -> {
final List<Employee> employees = session.createQuery( "from Employee", Employee.class )
.getResultList();
assertEquals( 2, employees.size() );
assertTrue( Editor.class.isInstance( employees.get( 0 ) ) );
assertTrue( Writer.class.isInstance( employees.get( 1 ) ) );
final Editor editor = (Editor) employees.get( 0 );
assertEquals( "Senior Editor", editor.getTitle() );
final Writer writer = (Writer) employees.get( 1 );
assertEquals( "Writing", writer.getTitle() );
assertNotNull( writer.getGroup() );
final Group group = writer.getGroup();
assertEquals( writer.getTitle(), group.getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee where title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryByRootClassAndOverridenPropertyTreat() {
doInHibernate( this::sessionFactory, session -> {
final Employee editor = session.createQuery( "from Employee e where treat( e as Editor ).title=:title", Employee.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Employee writer = session.createQuery( "from Employee e where treat( e as Writer).title=:title", Employee.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Test
public void testQueryBySublassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final Editor editor = session.createQuery( "from Editor where title=:title", Editor.class )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Writer writer = session.createQuery( "from Writer where title=:title", Writer.class )
.setParameter( "title", "Writing" )
.getSingleResult();
assertNotNull( writer.getGroup() );
assertEquals( writer.getTitle(), writer.getGroup().getName() );
});
}
@Test
public void testCriteriaQueryByRootClassAndOverridenProperty() {
doInHibernate( this::sessionFactory, session -> {
final CriteriaBuilder builder = session.getCriteriaBuilder();
final CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
final Root<Employee> root = query.from( Employee.class );
final ParameterExpression<String> parameter = builder.parameter( String.class, "title" );
final Predicate predicateEditor = builder.equal(
builder.treat( root, Editor.class ).get( "title" ),
parameter
);
query.where( predicateEditor );
final Employee editor = session.createQuery( query )
.setParameter( "title", "Senior Editor" )
.getSingleResult();
assertTrue( Editor.class.isInstance( editor ) );
final Predicate predicateWriter = builder.equal(
builder.treat( root, Writer.class ).get( "title" ),
parameter
);
query.where( predicateWriter );
final Employee writer = session.createQuery( query )
.setParameter( "title", "Writing" )
.getSingleResult();
assertTrue( Writer.class.isInstance( writer ) );
assertNotNull( ( (Writer) writer ).getGroup() );
assertEquals( writer.getTitle(), ( (Writer) writer ).getGroup() .getName() );
});
}
@Before
public void setupData() {
doInHibernate( this::sessionFactory, session -> {
Job jobEditor = new Job("Edit");
jobEditor.setEmployee(new Editor("Jane Smith", "Senior Editor"));
Job jobWriter= new Job("Write");
jobWriter.setEmployee(new Writer("John Smith", new Group("Writing")));
Employee editor = jobEditor.getEmployee();
Employee writer = jobWriter.getEmployee();
Group group = Writer.class.cast( writer ).getGroup();
session.persist( editor );
session.persist( group );
session.persist( writer );
session.persist( jobEditor );
session.persist( jobWriter );
});
}
@After
public void cleanupData() {
doInHibernate( this::sessionFactory, session -> {
session.createQuery( "delete from Job" ).executeUpdate();
session.createQuery( "delete from Employee" ).executeUpdate();
session.createQuery( "delete from Group" ).executeUpdate();
});
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Employee.class,
Editor.class,
Writer.class,
Group.class,
Job.class
};
}
@Entity(name="Employee")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(name="department")
public static abstract class Employee {
private String name;
private String title;
protected Employee(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@Transient
public String getTitle() {
return title;
}
protected Employee() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setTitle(String title) {
this.title = title;
}
}
@Entity(name = "Editor")
public static class Editor extends Employee {
public Editor(String name, String title) {
super(name);
setTitle( title );
}
@Column(name = "e_title")
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Editor() {
// this form used by Hibernate
super();
}
}
@Entity(name = "Writer")
public static class Writer extends Employee {
private Group group;
public Writer(String name, Group group) {
super(name);
setGroup(group);
}
// Cannot have a constraint on e_title because
// Editor#title (which uses the same e_title column) can be non-null,
// and there is no associated group.
@ManyToOne(optional = false)
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
public Group getGroup() {
return group;
}
@Column(name = "e_title", insertable = false, updatable = false)
public String getTitle() {
return super.getTitle();
}
public void setTitle(String title) {
super.setTitle( title );
}
protected Writer() {
// this form used by Hibernate
super();
}
protected void setGroup(Group group) {
this.group = group;
setTitle( group.getName() );
}
}
@Entity(name = "Group")
@Table(name = "WorkGroup")
public static class Group {
private String name;
public Group(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
protected Group() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
}
@Entity(name = "Job")
public static class Job {
private String name;
private Employee employee;
public Job(String name) {
this();
setName(name);
}
@Id
public String getName() {
return name;
}
@OneToOne
@JoinColumn(name="employee_name")
public Employee getEmployee() {
return employee;
}
protected Job() {
// this form used by Hibernate
}
protected void setName(String name) {
this.name = name;
}
protected void setEmployee(Employee e) {
this.employee = e;
}
}
}