我正在使用JPA编写Java EE应用程序,它需要国际化。
为此,我创建了一个名为MultilingualString
的课程,该课程将Language
与String
相关联
(以及如此扩展HashMap<Language, String>
)如下:
/**
* This class is mapped to the database thanks
* to the Locale.toLanguageTag() method
* and Locale.fromLanguageTag(String) constructor
*/
public class Language {
public Locale locale;
/* Getters, Setters ... */
}
/**
* NB : This class extends HashMap to override the put method
* which needs to ignore putting null values instead of throwing
* a NullPointerException
*/
public class MultilingualString extends HashMap<Language, String> {
public Map<Language, String> getStrings() {
return (this);
}
/* ... */
}
现在,我们假设Entity
的名称不同,具体取决于Language
:
@Entity
@Access(AccessType.PROPERTY)
public class Entity {
private Long id;
private MultilingualString name;
@Id
public Long getId() { ... }
@Transient
public MultilingualString getName() { ... }
@ElementCollection
@MapKeyJoinColumn(name = "language_id")
public Map<Language, String> getStrings() {
return (this.name.getStrings());
}
/* ... */
}
此代码生成以下数据库架构:
Language :
id | bigint | NOT NULL | primary key
languageTag | character varying(255) | |
---------------------------------------------------------------------------------------------------
Entity :
id | bigint | NOT NULL | primary key
---------------------------------------------------------------------------------------------------
Entity_strings :
entity_id | bigint | | foreign key references Entity(id)
language_id | bigint | | foreign key references Language(id)
string | character varying(255) | |
这几乎是好的。
此实现的问题是重复@Transient
字段上的MultilingualString
和@ElementCollection @MapKeyJoinColumn
方法上的getStrings()
(每次都必须重写)
您需要在数据库BTW中映射MultilingualString
:每个实体类至少1个)。
在我看来,它使代码变得难看并且难以维护。
另一件事是:Entity
将Language
与String
和Map
相关联。
应该有一个关联它们的课程:在我读的时候说LocalizedString
here
所以我希望MultilingualString
的行为类似于值类型
我不需要重复上面提到的那些多个注释并实现LocalizedString
。
以下是我到目前为止所提出的内容。它不起作用,GlassFish不会开始
使用这样的映射,当EclipseLink看到java.util.NoSuchElementException
映射时,我总是得到MultilingualString
。
@Embeddable
public class LocalizedString {
@ManyToOne
private Language language;
private String string;
}
@Embeddable
public class MultilingualString extends HashMap<Language, LocalizedString> {
/**
* Here I lost myself in all the available annotations
* and tried thousands of permutation, but always the same exception
* @MapKeyJoinColumn ?
* @MapKeyClass ?
* @CollectionTable ?
* ...
*/
@ElementCollection
public Map<Language, LocalizedString> getStrings() {
return (this);
}
}
@Entity
public class Entity {
@Id
private Long id;
@Embedded
private MultilingualString name;
}
因此,我希望通过此实现获得与上面所述相同(或最接近的)数据库映射。
这甚至可能吗?我读到Embeddable
类不应该包含另一个({1}}类的集合,但在这里,对我来说就是这种情况。
我阅读了几篇文章和博客,并没有发现像这样的很多情况(&#34; JPA Map with Entity key and Embeddable value&#34;)
实际上,我尝试做类似this的事情
除了我的地图值是Embeddable
类。
我找到了ONE similar situation
(除了我希望他的Embeddable
类是Root
)在StackOverflow上,我测试了一个答案(没有运气),但它没有被标记为答案&#34;这个问题没有取得多大成功。
答案 0 :(得分:0)
以下是可以处理实体本地化的方面示例:
@Aspect
public class LocalizationAspect {
@AfterReturning(
pointcut = "@within(MyManager) && execution(MyEntity methodThatReturnsEntity(..))",
returning = "entity"
)
public void localizeMyEntity(MyEntity entity) {
localize(entity);
}
}
通过微小的更改,您可以将其应用于返回实体的集合......
localie()在返回结果之前使用实体ID导航并将本地化信息注入该实体。