我正在編寫一個應用程序,其中所有字符串屬性都必須進行本地化,即它們必須爲每個可用的語言環境存儲不同的值。 一個快速的解決辦法是使用地圖,它可以在Hibernate中很容易映射,但不是很好的Java程序員:在Hibernate中映射一個本地化的字符串 - 任何最佳實踐?
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任務創建了兩個表,一個「產品」表和一個包含鍵和值列的「Products_localStrings」表。
@Embedded
public LocalString getNote() {
return note;
}
第二屬性不會在模式顯示:當我添加了吸氣的第二個屬性 一切打破。 我嘗試使用@AttributesOverride標籤爲兩列定義不同的名稱,但生成的模式是不正確的:
@Embedded
@AttributeOverrides({
@AttributeOverride(name="localStrings", [email protected](name="description"))
})
public LocalString getDescription() {
return description;
}
@Embedded
@AttributeOverrides({
@AttributeOverride(name="localStrings", [email protected](name="note"))
})
public LocalString getNote() {
return note;
}
在生成的模式,關鍵柱已經消失,主鍵用途「說明」 ,這是不正確的:
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.Apr.05
我已經使用了一段時間的地圖解決方案(與@ElementCollection註釋)一直,直到我偶然發現了兩個問題:
- 當前的Criteria API不適用於嵌入式集合:http://opensource.atlassian.com/projects/hibernate/browse/HHH-3646
- 當前的Hibernate Search(Lucene)API不適用於嵌入式集合:http://opensource.atlassian.com/projects/hibernate/browse/HSEARCH-566
我知道有很多解決方法,如使用的,而不是標準HQL和定義自己的FieldBridge拿地圖在Lucene的照顧,但我不喜歡的解決方法:他們的工作,直到下一個問題惡有惡報。 所以我現在下面這個方法:
我定義一個類「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;
}
通過這種方法,我必須爲每個需要本地化的屬性編寫一個空類,這需要爲該屬性創建一個唯一的表。 好處是我可以不受限制地使用Criteria和Search。
進一步的實驗顯示AttributeOverrides將地圖的鍵和值列都摺疊爲一個列。 – xtian 2011-01-28 15:21:27
我嘗試了一個xml映射,我設法得到了一個有效的模式,但由Hibernate生成的sql將每個屬性存儲在不同的插入中,結束於主鍵約束衝突。 – xtian 2011-01-28 15:23:12