【问题标题】:Populate database table with enum values in hibernate在休眠中使用枚举值填充数据库表
【发布时间】:2011-04-11 15:01:59
【问题描述】:

是否有可能让 Hibernate (3.6) 使用给定枚举的值填充数据库表? 我有以下课程:

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

我可以使用这个枚举,而另一个实体类没有任何问题

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

我的问题是,如何自动填充相应的表 ROLE ? 所有底层逻辑和定义都存在于 XML 规范中。当然,我可以通过 XSL 从这个规范生成一个 sql 文件,然后让 Hibernate 在启动时通过 import.sql 语义导入这个文件......但是有没有更优雅的方式?

表格应如下所示:

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

【问题讨论】:

    标签: hibernate enums


    【解决方案1】:

    你必须选择一方——要么使用Role 作为枚举,要么作为实体。你试图同时做这两件事,这只会导致麻烦。

    如果你想使用枚举

    • Role 中删除@Entity 注释。它不是实体,它没有主键。它也不应该是可变的,所以持久化它没有什么意义。
    • 从数据库中删除Roles(或其他任何名称)表。 Hibernate 按名称(如果您使用@Enumerated(EnumType.STRING) 映射)或通过values() 数组中的索引(如果您使用@Enumerated(EnumType.ORDINAL) 注释)来持久化枚举。无论哪种方式,它都不会引用您的附加表。有了你的映射 (@Enumerated(EnumType.STRING)),以 RoleID 开头毫无意义。

    如果你想使用实体

    • 使Role 成为一个真正的实体——带有getter / setter 和标识符的POJO。它可能是可变的,也可能不是可变的,这取决于你想要什么。
    • 将其映射到您的“角色”表。
    • 在您的其他表中将其引用为 @ManyToOne
    • 您必须自己填充表格; Hibernate 没有内置的方式来为你做这件事。

    【讨论】:

    • "您必须自己填充表格;Hibernate 没有内置的方法可以为您完成。"谢谢。在整个互联网上寻找该声明,但找不到任何东西..现在我可以停止寻找了。一个25k的答案是名副其实的^^
    • 我会告诫不要使用序数,因为只需要一个初级程序员不知道序数很重要,然后将其添加到顶部或中间即可为您搞乱整个数据库的其余部分。在枚举本身中使用常量,可以是字符串,也可以使用 int id 字段并将其持久化。
    【解决方案2】:

    这很好地填充了我的数据库

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

    【讨论】:

      【解决方案3】:

      您可以通过映射到“枚举表”来实现在数据库中的角色列中具有“数字 id”。要考虑 postgresql 原生枚举类型及其与其他方法的比较,请务必阅读https://vladmihalcea.com/the-best-way-to-map-an-enum-type-with-jpa-and-hibernate/

      我建议以顺序方式插入方便的“可能的枚举值表”:

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

      使用枚举的所需实体:

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

      与单元测试相比,确保序数始终相同,并且在项目的架构迁移部分中,将枚举插入数据库,以使数据库人员使用它们来进行良好的连接:

      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
      )
      

      STRING 方法的优势:

      • 数据库人员会更开心(作为您的数据库)
      • 您将存储足够的信息(使用@Column(columnDefinition = "smallint") 来控制使用的数据类型)
      • 有可能使用连接到 otherClass_role_info 表在数据库中获得人类可读的信息(如果需要,可以在 OtherClass.role 列上使用“switch/case”而不是连接到 otherClass_role_info.id)

      缺点:

      • 您应牢记(或在单元测试中)不应更改枚举的顺序
      • 自动(或手动使用架构迁移)将内容插入 otherClass_role_info 表的过程

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-08
        相关资源
        最近更新 更多