在休眠中使用枚举值填充数据库表

发布于 2024-10-31 17:49:56 字数 672 浏览 0 评论 0原文

是否有可能让 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|
....

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

守望孤独 2024-11-07 17:49:57

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

如果您想使用枚举

  • Role中删除@Entity注释。它不是一个实体,它没有主键。它也不应该是可变的,因此坚持它没有什么意义。
  • 从数据库中删除Roles(或任何名称)表。 Hibernate 按名称(如果您使用 @Enumerated(EnumType.STRING) 映射)或按 values() 数组中的索引(如果您使用 >@Enumerated(EnumType.ORDINAL) 注释)。无论哪种方式,它都不会引用您的附加表。通过映射 (@Enumerated(EnumType.STRING)),一开始就有 RoleID 是没有意义的。

如果你想使用一个实体

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

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.
递刀给你 2024-11-07 17:49:57

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

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

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;
    }
 ...
泛滥成性 2024-11-07 17:49:57

您可以通过映射到“枚举表”来实现数据库中角色列中的“数字 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 表中的过程

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文