8

Я пишу приложение, в котором все свойства String должны быть локализованы, т. Е. Они должны хранить другое значение для каждого доступного Locale. Быстрое решение было бы использовать карту, которая может быть легко переведенный в спящий режим, но это не хорошо на 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 как Entity?

Любые альтернативные проекты?

спасибо.

EDIT

Я попытался с отображением XML, и мне удалось получить правильную схему, но вставки будут выпадать с первичным ключом нарушением, поскольку спящий режим генерирует две вставки вместо одного

<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); 

Log:

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' 

Как мне сообщить, что спящий режим генерирует только одну вставку, как показано ниже?

insert into libro_strings (ID, idx, descrizione, giudizio) values (?, ?, ?, ?) 

EDIT на 2011.Apr.05

Я использовал раствор карты на некоторое время (с аннотацией @ElementCollection), пока я не наткнулся на две проблемы:

Я знаю, что есть много обходных путей, как с помощью HQL вместо критериев и определения собственного FieldBridge заботиться о карте в Lucene, но мне не нравится обходные пути: они работают, пока следующая проблема не приходит , Так я теперь следующий такой подход:

я определяю класс «LocalString», который содержит локали и значение (Locale на самом деле код 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; 
    } 

При таком подходе я должен написать пустой класс для каждого свойства, которое мне нужно локализовать, что необходимо для создания уникальной таблицы для этого свойства. Выгода заключается в том, что я могу использовать критерии и поиск без ограничений.

+0

Дальнейшие эксперименты показывают, что AttributeOverrides сворачивает как ключ, так и столбец значений карты в один столбец. – xtian

+0

Я попытался с отображением xml, и мне удалось получить действительную схему, но sql, сгенерированный Hibernate, сохраняет каждое свойство в другой вставке, заканчивая нарушение ограничения первичного ключа. – xtian

+0

Честно говоря, это намного больше, чем у меня есть время на чтение, и я предполагаю, что в него включены несколько вопросов. Вы получаете гораздо лучшую поддержку, когда можете свести проблему к одному вопросу, который легко описать. –

ответ

1

Ваше сопоставление xml не работает, потому что вы сопоставили типы значений в одну и ту же таблицу. При использовании элемента или составного элемента данные обрабатываются как типы значений и относятся к классу, в котором он содержится. Для этого требуется его собственная таблица. Идентификатор уникален только в коллекции.

Либо отобразить его в качестве компонента:

<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 является юридическим лицом. Ему нужен идентификатор и собственное определение отображения.

+0

Вы правы, я пытался использовать ту же таблицу для обеих карт, которая казалась приятной в начале, но теперь я понимаю, что это неправильно. – xtian

+0

В решении «независимая сущность» все локализованные строки моего приложения переходят в ту же таблицу LocalString. Я не хотел, чтобы это произошло, но теперь я понимаю, что я не сказал этого в своем вопросе. Приношу свои извинения за то, что я не понимаю этого. – xtian

+0

Аргумент «одна таблица против многих таблиц» - это что-то еще, что может стоить адресовать. – xtian

Смежные вопросы