[英]Hibernate extend entity for same table
I have a table with two fields I would like to have two objects. 我有一个有两个字段的表我希望有两个对象。
First one only has field1 第一个只有field1
@Entity(name = "simpleTableObject")
@Table(name = "someTable")
public class SimpleTableObject
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
protected long id;
@Column(name = "field1")
private String field1;
Second one has all two fields 第二个有两个领域
@Entity(name = "tableObject")
@Table(name = "someTable")
public class TableObject
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
protected long id;
@Column(name = "field1")
private String field1;
@Column(name = "field2")
private String field2;
I load each one using 我使用加载每一个
@Transactional(readOnly = true)
@SuppressWarnings("unchecked")
public List get(Class aClass)
{
ClassMetadata hibernateMetadata = sessionFactory.getClassMetadata(aClass);
if (hibernateMetadata == null)
{
return null;
}
if (hibernateMetadata instanceof AbstractEntityPersister)
{
AbstractEntityPersister persister = (AbstractEntityPersister) hibernateMetadata;
String tableName = persister.getTableName();
if (tableName != null)
{
return sessionFactory.getCurrentSession().
createQuery("from " + tableName).list();
}
}
return null;
}
What I would like to do is have TableObject
extend SimpleTableObject
. 我想做的是让TableObject
扩展SimpleTableObject
。 How would I go about doing that? 我该怎么做呢?
I was able to do something about your question. 我能够对你的问题做些什么。 I defined another class hierarchy: UserWithRole that extends User which is similar to yours. 我定义了另一个类层次结构:UserWithRole,它扩展了User,它类似于你的。
User
as an entity with inheritance strategy SINGLE_TABLE
: 将类User
定义为具有继承策略的实体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. 还有另一种策略JOINED
允许在子类中创建不可为空的列。 It creates an additional table for each subclass these tables have FK to the superclass table. 它为每个子类创建一个附加表,这些表具有FK到超类表。
UserWithRole
class: 定义UserWithRole
类: @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: 添加Helper
类以在数据库中创建用户并使用您的查询: @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: 获取所有User
实例: @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): 输出(具有角色的用户仍然是运行时的UserWithProfile
实例):
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: Hibernate发出的SQL查询:
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: 获取所有UserWithProfile
实例: @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: Hibernate发出的SQL查询:
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. 请告诉我这是你要找的。
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. 此外,您可以将SimpleTableObject
实体标记为@Immutable
如上所示,以便不会意外地@Immutable
或更新它。
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: 如果你想在你需要的表中保存公共字段意味着假设你有A类和B类,并且你有一些常见的字段,比如created_by,updated_by,你想在两个实体中保存field1,field2:IN数据库级别:
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 对于这种类型的结构,您应该使用@MapedSuperclass作为@Dragan Bozanovic建议
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 eg: Suppose you have 2 class Payment and CreditCard, Payment is parent class for CreditCard. 但是如果你想要Parent Child关系并希望每个类生成表,那么你可以使用@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)它将为每个类创建表格例如:假设你有2个类Payment和CreditCard,Payment是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. 在hibernate中使用了3种类型的继承,这里是hibernate doc for inheritance https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/InheritanceType.html ,你应该根据它选择任何一种你的要求。
Good question, I assume you have to look at @MappedSuperclass
anotation. 好问题,我假设您必须查看@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. 更新:由于你使用@Entity
anotation,你不必使用@Table
因为Hibernate会为你创建一个名为@Entity
表。
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. 你是否会有两个单独的DAO来分别检索TableObject
和SimpleTableObject
?如果是,你不需要扩展,只需将它们视为两个独立的实体。 If not, you can first get the TableObject and maybe create a constructor with SimpleTableObject(TableObject)
and copy all the fields you need there. 如果没有,您可以先获取TableObject,也可以使用SimpleTableObject(TableObject)
创建构造函数,并复制所需的所有字段。 I don't think it is possible to retrieve two entities with one findById
function. 我认为用一个findById
函数检索两个实体是不可能的。 Hibernate will be confused which entity to map to with the id, which means it doesn't make much sense to have the extend. Hibernate会混淆使用id映射到哪个实体,这意味着拥有扩展名没有多大意义。 If you want to keep the consistency, how about considering SimpleTableObject as a view of TableObjec. 如果要保持一致性,请将SimpleTableObject视为TableObjec的视图。
UPDATE : @Quillion I don't think it is possible this way. 更新 :@Quillion我认为不可能这样。 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. 由于这两个实体基本相同(您可以忽略实体中的某些字段),因此hibernate无法识别要映射的实体。 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. 当然你可以添加一个额外的列作为鉴别器,然后使用@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
映射这两个实体,但我认为这不是你想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.