2011-05-11 98 views
2

为了解决Java EE 6项目中对本地化动态(用户创建,存储在数据库中)数据的需求,我制作了一个通用本地化字符串表,该表能够存储任何语言的任何字符串。这样可以避免必须制作大约15个额外的表格,只是包含名称的东西。我想知道的是两两件事:JPA中可本地化的字符串

1)你认为这是一个很好的理念,为什么? 2)您是否知道在Cons中列出的问题的任何清洁解决方案?

我的经验:

优点:只有一个表需要的,通用的解决方案,易于无论是在JPA和DB配置。重复的代码是不存在的。

缺点:最大的问题,我觉得是由于muiltilingual_string表现在知道什么对象是使用它,级联删除将无法从SQL工作(但它在JPA工作与orphanRemoval)。如果从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) 
); 

回答

1

我看到的一个问题是,这似乎不像级联的ResourceBundle。

在ResourceBundle中,如果您的语言环境是ES_es,它将首先在ES_es中查找本地化版本,如果它未找到,则在ES中尝试,如果不是,则会查找默认字符串(如果它失败,将显示#STRING_ID字符串)。你可以有一个.EN字典,一个用于英国特定表达式的.EN_uk,一个用于表达美国特定表达式的.EN_us,而EN_uk和EN_us只能放置所需的键。

在您的系统中,它仅查看当前语言环境而不允许使用所有这些选项,因此您必须重新定义每个语言环境的所有值。因此,在上例中,您必须为EN_uk和EN_us中的每个键都设置一个值。

+0

在我的情况,包括不同的语言环境感觉有点小题大做,因为它只能处理纯文本,最有可能的不要超越使用两种语言。 – 2011-05-11 12:44:39