簡體   English   中英

在Hibernate中映射本地化的字符串-任何最佳實踐?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM