[英]Mapping a localized string in Hibernate - any best practice?
我正在編寫一個必須將所有String屬性都本地化的應用程序,即它們必須為每個可用的Locale存儲一個不同的值。 一種快速的解決方案是使用Map,該Map可以在Hibernate中輕松映射,但對Java程序員而言並不好:
public class Product {
private Map<Locale, String> description;
private Map<Locale, String> note;
因此,我實現了一個LocalString對象,該對象可以為不同的語言環境保存不同的字符串:
public class LocalString {
private Map<Locale, String> localStrings;
域對象變為
public class Product {
private LocalString description;
private LocalString note;
如何最好地用Hibernate注釋映射這些對象?
我認為最好的映射將使用LocalString作為組件來完成:
@Embeddable
public class LocalString {
private Map<Locale, String> localStrings;
@ElementCollection
public Map<Locale, String> getLocalStrings() {
return localStrings;
}
...
@Entity
public class Product {
private Long id;
private LocalString description;
private LocalString note;
@Embedded
public LocalString getDescription() {
return description;
}
到目前為止,一切都很好:hbm2ddl ant任務創建了兩個表,一個“產品”表和一個包含鍵和值列的“ Products_localStrings”表。 當我為第二個屬性添加吸氣劑時,一切都會中斷:
@Embedded
public LocalString getNote() {
return note;
}
第二個屬性未顯示在架構中。 我嘗試使用@AttributesOverride標記為兩列定義不同的名稱,但是生成的架構不正確:
@Embedded
@AttributeOverrides({
@AttributeOverride(name="localStrings", column=@Column(name="description"))
})
public LocalString getDescription() {
return description;
}
@Embedded
@AttributeOverrides({
@AttributeOverride(name="localStrings", column=@Column(name="note"))
})
public LocalString getNote() {
return note;
}
在生成的架構中,鍵列已消失,主鍵使用“ description”,這是不正確的:
create table Product_localStrings (Product_id bigint not null, note varchar(255), description varchar(255), primary key (Product_id, description));
有任何解決這個問題的方法嗎?
使用LocalString作為實體,如果沒有嵌入式組件,我會更好嗎?
還有其他設計嗎?
謝謝。
編輯
我嘗試了xml映射,但設法獲得了正確的架構,但由於主鍵沖突而導致插入失敗,因為hibernate生成了兩個插入,而不僅僅是一個
<hibernate-mapping>
<class name="com.yr.babka37.demo.entity.Libro" table="LIBRO">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="org.hibernate.id.enhanced.SequenceStyleGenerator"/>
</id>
<property name="titolo" type="java.lang.String">
<column name="TITOLO" />
</property>
<component name="descrizioni" class="com.yr.babka37.entity.LocalString">
<map name="localStrings" table="libro_strings" lazy="true" access="field">
<key>
<column name="ID" />
</key>
<map-key type="java.lang.String"></map-key>
<element type="java.lang.String">
<column name="descrizione" />
</element>
</map>
</component>
<component name="giudizi" class="com.yr.babka37.entity.LocalString">
<map name="localStrings" table="libro_strings" lazy="true" access="field">
<key>
<column name="ID" />
</key>
<map-key type="java.lang.String"></map-key>
<element type="java.lang.String">
<column name="giudizio" />
</element>
</map>
</component>
</class>
</hibernate-mapping>
該架構是
create table LIBRO (ID bigint not null auto_increment, TITOLO varchar(255), primary key (ID));
create table libro_strings (ID bigint not null, descrizione varchar(255), idx varchar(255) not null, giudizio varchar(255), primary key (ID, idx));
alter table libro_strings add index FKF576CAC5BCDBA0A4 (ID), add constraint FKF576CAC5BCDBA0A4 foreign key (ID) references LIBRO (ID);
日志:
DEBUG org.hibernate.SQL - insert into libro_strings (ID, idx, descrizione) values (?, ?, ?)
DEBUG org.hibernate.SQL - insert into libro_strings (ID, idx, giudizio) values (?, ?, ?)
WARN o.h.util.JDBCExceptionReporter - SQL Error: 1062, SQLState: 23000
ERROR o.h.util.JDBCExceptionReporter - Duplicate entry '5-ita_ITA' for key 'PRIMARY'
如何告訴hibernate僅生成一個如下所示的插入?
insert into libro_strings (ID, idx, descrizione, giudizio) values (?, ?, ?, ?)
編輯於2011年4月5日
我一直在使用Map解決方案一段時間(用@ElementCollection注釋),直到偶然發現兩個問題:
我知道有很多解決方法,例如使用HQL代替Criteria並定義自己的FieldBridge來處理Lucene中的Map,但是我不喜歡解決方法:它們會一直工作到下一個問題解決為止。 因此,我現在采用這種方法:
我定義一個包含語言環境和值的類“ LocalString”(該語言環境實際上是ISO3代碼):
@MappedSuperclass
public class LocalString {
private long id;
private String localeCode;
private String value;
然后,為要本地化的每個屬性定義一個LocalString的子類,該子類為空:
@Entity
public class ProductName extends LocalString {
// Just a placeholder to name the table
}
現在,可以在我的產品對象中使用它:
public class Product {
private Map<String, ProductName> names;
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="Product_id")
@MapKey(name="localeCode")
protected Map<String, ProductName> getNames() {
return names;
}
使用這種方法,我必須為需要本地化的每個屬性編寫一個空類,這是為該屬性創建唯一表所必需的。 好處是我可以不受限制地使用條件和搜索。
您的xml映射不起作用,因為您將值類型映射到了同一表中。 使用元素或復合元素時,數據被視為值類型,並且屬於其中包含的類。它需要自己的表。 該ID僅在集合中是唯一的。
可以將其映射為組件:
<component name="descrizioni">
<map name="localStrings" table="descrizioni_strings" ...>
<!-- ... -->
</map>
</component>
<component name="giudizi">
<map name="localStrings" table="giudizi_strings" ... >
<!-- ... -->
</map>
</component>
或作為獨立實體:
<many-to-one name="descrizioni" class="LocalString"/>
<many-to-one name="giudizi" class="LocalString"/>
在第二種情況下,LocalString是一個實體。 它需要一個ID及其自己的映射定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.