Dominik
Dominik

Reputation: 1431

Populate database table with enum values in hibernate

is there any possibility to let Hibernate (3.6) populate a database table with values for a given enum ? I have the following class:

@Entity
public enum Role
{
    ROLE_USER_FREE("ROLE_USER_FREE"),
    ROLE_USER_STANDARD("ROLE_USER_STANDARD"),
    ROLE_USER_PREMIUM("ROLE_USER_PREMIUM"),
    ROLE_ADMIN("ROLE_ADMIN");
    ... constructor / setter / getter etc.
}

I can use this enum without any problems from another entity class using

@Enumerated(EnumType.STRING)
public Role getRole()

My question is, how can I populate the corresponding table ROLE automatically ? All the underlying logic and definiations resides in an XML specification. Of course, I can generate a sql file from this spec by XSL and let Hibernate import this by the import.sql sematic at startup... But is there a more elegant way ?

The table should look like this:

|RoleID|RoleName      |
|  0   |ROLE_USER_FREE|
....

Upvotes: 5

Views: 8013

Answers (3)

Lubo
Lubo

Reputation: 1827

You can achieve having "numeric id" in role column in database with mapping to "enum table". To consider postgresql native enum type and its comparison to other approaches, be sure to read https://vladmihalcea.com/the-best-way-to-map-an-enum-type-with-jpa-and-hibernate/

I would suggest to go ordinal way with inserting convient "possible enum values table":

public enum Role
{
    ROLE_USER_FREE("ROLE_USER_FREE"),
    ROLE_USER_STANDARD("ROLE_USER_STANDARD"),
    ROLE_USER_PREMIUM("ROLE_USER_PREMIUM"),
    ROLE_ADMIN("ROLE_ADMIN");
    ... constructor / setter / getter etc.
}

Desired entity using enum:

@Entity
public class OtherClass {
    @Enumerated(EnumType.ORDINAL)
    @Column(columnDefinition = "smallint")
    public Role getRole()
}

Than in unit test ensure that ordinals are always same and also in schema migration part of you project insert enums to database to make them use by database guy to have nice joins possible:

CREATE TABLE otherClass_role_info (
    id SMALLINT NOT NULL,
    description VARCHAR(255),
    name VARCHAR(255),
    PRIMARY KEY (id)
)

INSERT INTO otherClass_role_info (
    description,
    name,
    id
)
VALUES (
    'Role for admins. Usually means that they can do things without further checking :/',
    'ROLE_ADMIN',
    3
)

Benefits over STRING approach:

  • database guys will be much happier (as your database)
  • you will store just enough information (use @Column(columnDefinition = "smallint") to controll data type used)
  • there is possibility to have human readable information in database using join to otherClass_role_info table (There is possibility to use "switch/case" on OtherClass.role column instead of join to otherClass_role_info.id if desired)

Downsides:

  • you should keep on mind (or in unit test) that order of your enum should not be changed
  • automate (or manually using schema migration) process of inserting things into otherClass_role_info table

Upvotes: 1

Ken
Ken

Reputation: 35

This populates my database fine

public class Person implements UserAccount
{
    public static enum Role
    {
        anon(6), admin(1), standard(4), manager(3), user(5), director(2);
        private int weight;

        Role(int weight)
        {
            this.weight = weight;
        }

        public int weight()
        {
            return weight;
        }
    }

    @ElementCollection(targetClass = Role.class, fetch=FetchType.EAGER)
        @Enumerated(EnumType.STRING) // Possibly optional (I'm not sure) but defaults to ORDINAL.
        @CollectionTable(name="person_roles")
        @Column(name="role") 
    public Set<Role> getRoles()
    {
        return roles;
    }
 ...

Upvotes: 4

ChssPly76
ChssPly76

Reputation: 100706

You have to pick a side - either you're going to use Role as enum or as entity. You're trying to do both and that's only going to lead to trouble along the road.

If you want to use enum

  • Remove @Entity annotation from Role. It's not an entity, it doesn't have a primary key. It also shouldn't be mutable, so there's little point in persisting it.
  • Remove Roles (or whatever it's called) table from the database. Hibernate persists enums by name (if you're using @Enumerated(EnumType.STRING) mapping) or by index in values() array (if you're using @Enumerated(EnumType.ORDINAL) annotation). Either way, it will never reference your additional table. With you mapping (@Enumerated(EnumType.STRING)) it's pointless to have RoleID to begin with.

If you want to use an entity

  • Make Role a true entity - POJO with getters / setters and identifier. It may or may not be mutable depending on what you want.
  • Map it to your 'Roles' table.
  • Reference it as @ManyToOne from your other tables.
  • You will have to populate the table yourself; there's no built-in way for Hibernate to do it for you.

Upvotes: 9

Related Questions