Hibernate扩展了同一个表的实体

我有一个有两个字段的表我希望有两个对象。

第一个只有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; 

第二个有两个领域

 @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; 

我使用加载每一个

 @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; } 

我想做的是让TableObject扩展SimpleTableObject 。 我该怎么做呢?

如果你想在你需要的表中保存公共字段意味着假设你有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 | +----+------------+------------+ 

对于这种类型的结构,您应该使用@MapedSuperclass作为@Dragan Bozanovic建议

但是如果你想要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; } } 

现在你将保存日期:

 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(); } } 

然后数据将保存

 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) 

在hibernate中使用了3种类型的inheritance,这里是hibernate doc for inheritance https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/InheritanceType.html ,你应该根据它们选择任何一种你的要求。

您可以为两个实体都有一个共同的超类:

 @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 } 

此外,您可以将SimpleTableObject实体标记为@Immutable如上所示,以便不会意外地持久化或更新它。

我能够对你的问题做些什么。 我定义了另一个类层次结构:UserWithRole扩展了User,它类似于你的。

将类User定义为具有inheritance策略的实体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. ... } 

这种inheritance策略有一个相当大的缺点:

  • 子类不能包含不可为空的列。

还有另一种策略JOINED允许在子类中创建不可为空的列。 它为每个子类创建一个附加表,这些表具有FK到超类表。

定义UserWithRole类:

 @Entity public class UserWithRole extends User { private String role; // toString(), default constructor, setters/getters, more constructors. ... } 

添加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; } } 

如您所见,我稍微改变了您的方法:

  • 添加了generics类型以避免不安全的类型转换;
  • 使用的实体名称而不是表名,因为HQL需要实体名称。

我们开始测试了

获取所有User实例:

 @Test public void testQueryUsers() { helper.createUsers(); for (User user: helper.get(User.class)) { System.out.println(user); } } 

输出(具有角色的用户在运行时仍为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'} 

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实例:

 @Test public void testQueryUsersWithProfile() { helper.createUsers(); for (User user: helper.get(UserWithRole.class)) { System.out.println(user); } } 

输出:

 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'} 

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' 

请告诉我这是不是你要找的东西。

好问题,我假设您必须查看@MappedSuperclass anotation。 它允许创建一个不会被实例化的“抽象”实体类,但是你可以从中扩展它。

请参阅此处的示例

更新:由于你使用@Entity anotation,你不必使用@Table因为Hibernate会为你创建一个名为@Entity表。

评论有点太长了,所以我必须在答案中写下来。

你是否会有两个单独的DAO来分别检索TableObjectSimpleTableObject ?如果是,你不需要扩展,只需将它们视为两个独立的实体。 如果没有,您可以先获取TableObject,也可以使用SimpleTableObject(TableObject)创建构造函数,并复制所需的所有字段。 我认为用一个findById函数检索两个实体是不可能的。 Hibernate会将哪个实体与id映射混淆,这意味着扩展它没有多大意义。 如果要保持一致性,请将SimpleTableObject视为TableObjec的视图。

更新 :@Quillion我认为不可能这样。 由于这两个实体基本相同(您可以忽略实体中的某些字段),因此hibernate无法识别要映射的实体。 当然你可以添加一个额外的列作为鉴别器,然后使用@Inheritance(strategy=InheritanceType.SINGLE_TABLE)映射这两个实体,但我认为这不是你想要的。