使用 JPA / Hibernate 进行国际化的最优雅的解决方案?

Gui*_*ssi 6 sql hibernate jpa internationalization

亲爱的 Stackflow 社区,

我希望在我的实体中存储国际化字符串,但我正在努力解决如何解决这个问题。我将在这里描述我能想到的两种解决方案,并希望收到您的反馈。

解决方案 1:从实体外部化

在此解决方案中,我的数据库中有下表:

LabelId         Language    VALUE   Entity              Id

WELCOME_TEXT    EN          "..."       Questionnaire   1
WELCOME_TEXT    DE          "..."       Questionnaire   1
GOODBYE_TEXT    EN          "..."       Questionnaire   1
GOODBYE_TEXT    DE          "..."       Questionnaire   1

QUESTION_TITLE  EN          "..."       Question        12
QUESTION_TITLE  DE          "..."       Question        12

OPTION_NAME     EN          "..."       Option          23
OPTION_NAME     DE          "..."       Option          23

FACTOR_NAME     EN          "..."       Factor          11
FACTOR_NAME     DE          "..."       Factor          11
Run Code Online (Sandbox Code Playgroud)

我总是使用以下方法访问该集合:

void setLabels(Entity entity, LabelId labelId, Map<String, String langValues)
Map<String, String> getLabels(Entity entity, LabelId labelId)
Run Code Online (Sandbox Code Playgroud)

解决方案 2:使用元素集合

在此解决方案中,所有实体都将 Map 存储在同一个表中:

LabelId         Language    VALUE   questionnaire_id    factor_id   question_id option_id

WELCOME_TEXT    EN          "..."       1
WELCOME_TEXT    DE          "..."       1
GOODBYE_TEXT    EN          "..."       1
GOODBYE_TEXT    DE          "..."       1

QUESTION_TITLE  EN          "..."                                   12
QUESTION_TITLE  DE          "..."                                   12

OPTION_NAME     EN          "..."                                               23
OPTION_NAME     DE          "..."                                               23

FACTOR_NAME     EN          "..."                       11
FACTOR_NAME     DE          "..."                       11
Run Code Online (Sandbox Code Playgroud)

然后,我将以以下格式映射实体中的所有字段:

i18n.java:

@Entity 
@Table(uniqueConstraints={@UniqueConstraint(columnNames={"label", "language", "questionnaire_id", "question_id", ... })})
public class i18n extends PersistentObject { // where it gets ID from
    Label label; // enum

    Language language; // enum

    String value; // the actual text

    // bi-directional links to the linked entities
    @ManyToOne Questionnaire questionnaire;
    @ManyToOne Question question;
    ...
}
Run Code Online (Sandbox Code Playgroud)

问卷.java:

@OneToMany(mappedBy = "questionnaire")
List<i18n> labels;
Run Code Online (Sandbox Code Playgroud)

问题.java:

@OneToMany(mappedBy = "question")
List<i18n> labels;
Run Code Online (Sandbox Code Playgroud)

解决方案3:非解决方案

另一种简单的方法是为每个属性简单地存储这样的地图:

@ElementCollection
Map<String, String> welcomeText;

@ElementCollection
Map<String, String> goodbyeText;

...
Run Code Online (Sandbox Code Playgroud)

这个解决方案在我的数据库中创建了大量的表,这将使查询和维护变得混乱。

结论

第一个解决方案为我提供了更好的表格,但代价是每次需要时都必须通过附加服务检索标签。第二种解决方案保持实体的代码干净,但 SQL 表很混乱,所有需要翻译的实体都有许多列。

你会如何处理这个问题?有更好的解决方案吗?

预先感谢所有反馈!

Gui*_*ssi 2

我用描述的第一种方法解决了这个问题。此外,我使用PreparedStatements 缓存了查询,它们的性能非常好。除了设置单个翻译之外,我还创建了批量编辑和批量检索方法,效果更好。