I have a table with two fields I would like to have two objects.
First one only has field1
@Entity(name = \"simpleTableObject\")
@Table(name = \"someTabl
I was able to do something about your question. I defined another class hierarchy: UserWithRole that extends User which is similar to yours.
User
as an entity with inheritance strategy SINGLE_TABLE
:@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "USERS")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@Column(nullable = false)
protected String name;
// toString(), default constructor, setters/getters, more constructors.
...
}
This inheritance strategy has one considerable disadvantage:
There is another strategy JOINED
that allows creating non-nullable columns in subclasses. It creates an additional table for each subclass these tables have FK to the superclass table.
UserWithRole
class:@Entity
public class UserWithRole extends User {
private String role;
// toString(), default constructor, setters/getters, more constructors.
...
}
Helper
class to create users in the database and use your query:@Component
public class Helper {
@Autowired
EntityManager entityManager;
@Transactional
public void createUsers() {
for (long i = 0; i < 10; i++) {
User user;
if (i % 2 == 0) {
user = new UserWithRole("User-" + i, "Role-" + i);
} else {
user = new User("User-" + i);
}
entityManager.persist(user);
}
entityManager.flush();
}
@Transactional(readOnly = true)
@SuppressWarnings("unchecked")
public < T > List < T > get(Class < T > aClass) {
SessionFactory sessionFactory = entityManager.getEntityManagerFactory().unwrap(SessionFactory.class);
ClassMetadata hibernateMetadata = sessionFactory.getClassMetadata(aClass);
if (hibernateMetadata == null) {
return null;
}
if (hibernateMetadata instanceof AbstractEntityPersister) {
AbstractEntityPersister persister = (AbstractEntityPersister) hibernateMetadata;
String entityName = persister.getEntityName();
if (entityName != null) {
return sessionFactory.getCurrentSession().
createQuery("from " + entityName).list();
}
}
return null;
}
}
As you may see, I changed your method a bit:
User
instances:@Test
public void testQueryUsers() {
helper.createUsers();
for (User user: helper.get(User.class)) {
System.out.println(user);
}
}
Output (users with role are still UserWithProfile
instances at runtime):
UserWithRole{id=1, name='User-0', role='Role-0'}
User{id=2, name='User-1'}
UserWithRole{id=3, name='User-2', role='Role-2'}
User{id=4, name='User-3'}
UserWithRole{id=5, name='User-4', role='Role-4'}
User{id=6, name='User-5'}
UserWithRole{id=7, name='User-6', role='Role-6'}
User{id=8, name='User-7'}
UserWithRole{id=9, name='User-8', role='Role-8'}
User{id=10, name='User-9'}
SQL query issued by Hibernate:
select
user0_.id as id2_0_,
user0_.name as name3_0_,
user0_.role as role4_0_,
user0_.dtype as dtype1_0_
from
users user0_
UserWithProfile
instances:@Test
public void testQueryUsersWithProfile() {
helper.createUsers();
for (User user: helper.get(UserWithRole.class)) {
System.out.println(user);
}
}
Output:
UserWithRole{id=1, name='User-0', role='Role-0'}
UserWithRole{id=3, name='User-2', role='Role-2'}
UserWithRole{id=5, name='User-4', role='Role-4'}
UserWithRole{id=7, name='User-6', role='Role-6'}
UserWithRole{id=9, name='User-8', role='Role-8'}
SQL query issued by Hibernate:
select
userwithro0_.id as id2_0_,
userwithro0_.name as name3_0_,
userwithro0_.role as role4_0_
from
users userwithro0_
where
userwithro0_.dtype = 'UserWithRole'
Please, let me know if it's what you were looking for.
If you want save common fields in your required tables means suppose you have class A and B and you have some common filed like created_by,updated_by and you want to save field1,field2 in both entity: IN database level:
query> select * from A;
+----++------------------------+
| id | created_by | updated_by |
+----+------------+------------+
| 3 | xyz | abc |
+----+------------+------------+
query> select * from B;
+----++------------------------+
| id | created_by | updated_by |
+----+------------+------------+
| 3 | xyz | abc |
+----+------------+------------+
for this type of structure you should use @MappedSuperclass as @Dragan Bozanovic suggested
But if you want Parent Child relation and want generate table per class then you can use @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) it will create table per class e.g: Suppose you have 2 class Payment and CreditCard, Payment is parent class for CreditCard.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private int id;
@Column(nullable = false)
private double amount;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}
@Entity
public class CreditCard extends Payment {
private String ccNumber;
private Date expireDate;
public String getCcNumber() {
return ccNumber;
}
public void setCcNumber(String ccNumber) {
this.ccNumber = ccNumber;
}
public Date getExpireDate() {
return expireDate;
}
public void setExpireDate(Date expireDate) {
this.expireDate = expireDate;
}
}
Now you will save date :
public class TestConcreteClasses {
public static void main(String[] args) {
Payment payment = new Payment();
payment.setAmount(52.6);
createData(payment);
CreditCard creditCard = new CreditCard();
creditCard.setAmount(10);
creditCard.setCcNumber("2536985474561236");
creditCard.setExpireDate(new Date());
createData(creditCard);
}
private static void createData(Payment instance) {
Session session = HibernateUtil.getSession();
session.beginTransaction();
session.save(instance);
session.getTransaction().commit();
}
}
then data will save like
query> select * from Payment;
+----+--------+
| id | amount |
+----+--------+
| 1 | 52.6 |
+----+--------+
1 row in set (0.00 sec)
select * from CreditCard;
+----+--------+------------------+---------------------+
| id | amount | ccNumber | expireDate |
+----+--------+------------------+---------------------+
| 2 | 10 | 2536985474561236 | 2017-03-12 14:10:15 |
+----+--------+------------------+---------------------+
1 row in set (0.00 sec)
There are 3 types of inheritance used in hibernate, here is hibernate doc for inheritance https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/InheritanceType.html, you should pick any of them according to your requirement.
Good question, I assume you have to look at @MappedSuperclass
anotation. It allows to make an "abstract" entity class that would not be instantiated, however you can extend from that.
See example of that here
Update: Since you use @Entity
anotation, you dont have to use @Table
since Hibernate will create table named @Entity
for you.
The comment is a bit too long, so I have to write it in the answer.
Are you going to have two separate DAO to retrieve TableObject
and SimpleTableObject
separately?If yes, you don't need the extend, just treat them as two separate entities. If not, you can first get the TableObject and maybe create a constructor with SimpleTableObject(TableObject)
and copy all the fields you need there. I don't think it is possible to retrieve two entities with one findById
function. Hibernate will be confused which entity to map to with the id, which means it doesn't make much sense to have the extend. If you want to keep the consistency, how about considering SimpleTableObject as a view of TableObjec.
UPDATE : @Quillion I don't think it is possible this way. Since these two entities are basically identical(you can ignore some fields in an entity), there is no way for hibernate to identify which entity to map. Of course you can add an extra column as a discriminator, then use the @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
to map these two entities, but I assume this is not what you want.
You can have a common superclass for both entities:
@MappedSuperclass
public abstract class AbstractTableObject {
// common mappings
}
@Entity
@Table(name = "someTable")
public class TableObject extends AbstractTableObject {
// remaining mappings
}
@Entity
@Table(name = "someTable")
@Immutable
public class SimpleTableObject extends AbstractTableObject {
// nothing here
}
Additionally, you can mark the SimpleTableObject
entity to be @Immutable as shown above, so that it cannot be persisted or updated accidentally.