java - 如何国际化 Hibernate 实体

标签 java hibernate jpa internationalization

我正在尝试为 Java 实体添加国际化(多语言)支持。在向每个新字段添加翻译时,我愿意接受尽可能少的样板代码的任何选项。我不限于 JPA,也可以使用 hibernate 注释。在最坏的情况下,纯 sql 也适用。可能有一些我还没有找到的现成库。 应该没有必要遵循我下面描述的想法。

理想情况下,我需要数据库看起来像这样:

i18n
+------+--------+------+
|  id  | locale | text |
+------+--------+------+
|  1   |   en   | foo  |
+------+--------+------+
|  1   |   de   | bar  |
+------+--------+------+
|  2   |   en   | foo2 |
+------+--------+------+
|  2   |   de   | bar2 |
+------+--------+------+

parent
+------+------+
|  id  | text |
+------+------+
|  99  |   1  |
+------+------+
|  100 |   2  |
+------+------+

i18n 是一个应该只包含 3 列的表:idlocaletext。表 parent 有一列 text(如果只有一个字段需要 i18n,否则需要更多列)包含来自 i18n.id 的值。我在父类中尝试了以下映射:

@ElementCollection @CollectionTable(name="i18n", joinColumns = @JoinColumn(referencedColumnName="id"))
@MapKeyColumn(name="locale") @Column(name="text")
public Map<String, String> text = newHashMap();

当禁用 DDL 生成并且我自己创建表时它似乎可以工作,但是当启用 DDL 生成时,它会生成一个不必要的列 i18n.parent_id 和一个约束:

ALTER TABLE PUBLIC.I18N ADD CONSTRAINT 
PUBLIC.FK_HVGN9UJ4DJOFGLT8L78BYQ75I FOREIGN KEY(PARENT_ID) INDEX 
PUBLIC.FK_HVGN9UJ4DJOFGLT8L78BYQ75I_INDEX_2 REFERENCES 
PUBLIC.PARENT(ID) NOCHECK

如何去掉这个多余的列?是否可以避免从 i18n 表到 parent 表的引用?此链接使重用 i18n 表变得困难。我要么需要在 i18n 表中保留一些鉴别器值,要么在整个数据库中使用 GUID,因为不同表中的 id 会发生冲突。第一个选项意味着很多样板代码。第二个选项意味着当前项目中有很多工作要做。

我需要一种可重用的方法来将国际化添加到实体中。我的父类将大致像这样。并且会有几个这样的父类具有必须国际化的不同的字段集

@Entity
public class Parent {

    @Id @GeneratedValue
    public Long id;

    public String title; // must be in internationalized
    public String text; // must be in internationalized
    public String details; // must be in internationalized

    // ... other fields
}

最佳答案

On the database level collection instances are distinguished by the foreign key of the entity that owns the collection. This foreign key is referred to as the collection key column, or columns, of the collection table.

所以我想你想为你的提议禁用 forgien key 生成,简单地说你可以这样做

@Entity
public class Parent {

    @Id
    @GeneratedValue
    public Long id;

    @ElementCollection
    @CollectionTable(name = "i18n", foreignKey = @ForeignKey(name = "none"), joinColumns = @JoinColumn(name = "id"))
    @MapKeyColumn(name = "locale")
    @Column(name = "text")
    public Map<String, String> text = new HashMap<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Map<String, String> getText() {
        return text;
    }

    public void setText(Map<String, String> text) {
        this.text = text;
    }
}

然后当你验证生成的DDL时,forgien key并没有应用到I18N表上,但是还是得到了能力

@Test
public void testParent() {
    Parent p = new Parent();
    HashMap<String, String> text = new HashMap<>();
    text.put("en", "foo");
    text.put("de", "bar");
    p.setText(text);

    entityManager.persist(p);
    entityManager.flush();

    Parent parent = entityManager.find(Parent.class, p.getId());
    System.out.println("en: " + parent.getText().get("en"));
    System.out.println("de: " + parent.getText().get("de"));
}

about是一个简单的测试(Spring Boot 1.4 release),会在控制台看到输出:

Hibernate: 
    create table i18n (
        id bigint not null,
        text varchar(255),
        locale varchar(255) not null,
        primary key (id, locale)
    )
Hibernate: 
    create table parent (
        id bigint generated by default as identity,
        primary key (id)
    ) 
......
Hibernate: 
    insert 
    into
        parent
        (id) 
    values
        (null)
Hibernate: 
    insert 
    into
        i18n
        (id, locale, text) 
    values
        (?, ?, ?)
Hibernate: 
    insert 
    into
        i18n
        (id, locale, text) 
    values
        (?, ?, ?)
en: foo
de: bar

这是 H2 数据库中的表:

enter image description here

关于java - 如何国际化 Hibernate 实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39704729/

相关文章:

java - Java 抽象 2D 几何库

java - Hibernate 持久映射

hibernate - 使用Oracle 11g hibernate (严重)-权限不足

java - 使用 Jpa 和 Thymeleaf 在 Spring Boot 中重定向页面

java - 如何检查类名中是否存在单词?

java - 使用 Hibernate 时出现 OutOfMemory 错误的最常见原因是什么?

java - 使用 JPA 从外国实体获取一定的值(value)

java - 容器管理的持久性和创建临时表的存储过程

java - 部署时 persistence.xml 中的 Manege jta-data-source

java - 如何根据我的 REST API 实现操作