为了解决在Java EE 6项目中对本地化动态(用户创建,存储在db中)数据的需求,我制作了一个通用的本地化字符串表,它能够以任何语言存储任何字符串。这样可以避免只需要包含15个附加表的内容。我想知道的是两件事:
1)你认为这是一个好或坏的想法,为什么? 2)您是否知道对Cons下列出的问题有任何清洁的解决方案?
我的经历:
优点:只需要一个表,一般解决方案在jpa和db中都很容易配置。重复的代码是不存在的。
缺点:我发现的一个大问题是,由于muiltilingual_string表现在知道哪些对象正在使用它,因此级联删除将无法在SQL中运行(但它在带有orphanRemoval的JPA中有效)。如果从JPA外部工作,这就产生了“死”字符串保留在数据库中的可能性。
实体:( AbstractEntity是一个包含@id和@version的映射超类)
@Entity
@Table(schema = "COMPETENCE", name = "multilingual_string")
public class MultilingualString extends AbstractEntity{
@ElementCollection(fetch=FetchType.EAGER)
@MapKey(name = "language")
@CollectionTable(schema = "COMPETENCE", name = "multilingual_string_map",
joinColumns = @JoinColumn(name = "string_id"))
private Map<Language, LocalizedString> map = new HashMap<Language, LocalizedString>();
public MultilingualString() {}
public MultilingualString(Language lang, String text) {
addText(lang, text);
}
public void addText(Language lang, String text) {
map.put(lang, new LocalizedString(lang, text));
}
public String getText(Language lang) {
if (map.containsKey(lang)) {
return map.get(lang).getText();
}
return null;
}
public LocalizedString getLocalizedString(Language lang){
if(map.get(lang) == null)
map.put(lang, new LocalizedString(lang, null));
return map.get(lang);
}
@Override
public MultilingualString clone(){
MultilingualString ms = new MultilingualString();
for(LocalizedString s : map.values())
ms.addText(s.getLanguage(), s.getText());
return ms;
}
@Override
public String toString() {
return getId() == null ? "null " + this.getClass().getName() : getId().toString();
}
}
@Embeddable
public class LocalizedString {
@JoinColumn(name="lang_id")
private Language language;
@Column(name="text")
private String text;
public LocalizedString() {
}
public LocalizedString(Language language, String text) {
this.language = language;
this.text = text;
}
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
这些类在其他实体中使用如下:
@OneToOne(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name = "summary_stringid")
private MultilingualString summary;
表格:
MULTILINGUAL_STRING (
id bigint primary key
);
MULTILINGUAL_STRING_MAP (
string_id bigint FOREIGN KEY REFERENCES MULTILINGUAL_STRING(id),
lang_id bigint FOREIGN KEY REFERENCES LANG(id),
text varchar(2000 char),
PRIMARY KEY(string_id, lang_id)
);
用作以下内容:
COMPETENCE (
id bigint PRIMARY KEY,
name_id bigint FOREIGN KEY REFERENCES MULTILINGUAL_STRING(id)
);
答案 0 :(得分:1)
我看到的一个问题是,这似乎不像ResourceBundle的级联那样有效。
在ResourceBundle中,如果您的语言环境是ES_es,它将首先在ES_es中查找本地化版本,如果找不到将在ES中尝试,如果没有,它将查找默认字符串(如果它失败,它将显示#STRING_ID字符串)。你可以有一个.EN字典,一个.EN_uk用于特定于英国的表达式,一个.EN_us用于特定于美国的表达式,在EN_uk和EN_us中只放置所需的密钥。
使用您的系统,它只查看当前区域设置而不允许所有这些选项,因此您必须重新定义每个区域设置的所有值。因此,在上面的示例中,您必须为EN_uk和EN_us为每个键设置一个值。
答案 1 :(得分:1)
这种方法确实有意义,并不是新的。 它是针对不同的JPA提供者在这里发布,讨论和测试的: http://hwellmann.blogspot.com/2010/07/jpa-20-mapping-map.html (我相信你从那里拿了代码)