Hibernate extend entity for same table

前端 未结 5 1058
猫巷女王i
猫巷女王i 2021-02-05 22:32

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         


        
5条回答
  •  滥情空心
    2021-02-05 23:14

    I was able to do something about your question. I defined another class hierarchy: UserWithRole that extends User which is similar to yours.

    Define class 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:

    • Subclasses can't contain non-nullable columns.

    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.

    Define UserWithRole class:

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

    Add 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:

    • Added generic type to avoid unsafe type casts;
    • Used entity name instead of table name because HQL expects entity name.

    Let's start testing

    Get all 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_
    

    Get all 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.

提交回复
热议问题