xti*_*ian 8 schema hibernate localization internationalization hibernate-mapping
我正在编写一个必须本地化所有String属性的应用程序,即它们必须为每个可用的Locale存储不同的值.一个快速的解决方案是使用Map,它可以在Hibernate中轻松映射,但对Java程序员来说不是很好:
public class Product {
private Map<Locale, String> description;
private Map<Locale, String> note;
Run Code Online (Sandbox Code Playgroud)
因此,我实现了一个LocalString对象,可以为不同的语言环境保存不同的字符串:
public class LocalString {
private Map<Locale, String> localStrings;
Run Code Online (Sandbox Code Playgroud)
域对象变为
public class Product {
private LocalString description;
private LocalString note;
Run Code Online (Sandbox Code Playgroud)
如何使用Hibernate注释最好地映射这些对象?
我认为最好的映射将使用LocalString作为组件完成:
@Embeddable
public class LocalString {
private Map<Locale, String> localStrings;
@ElementCollection
public Map<Locale, String> getLocalStrings() {
return localStrings;
}
Run Code Online (Sandbox Code Playgroud)
...
@Entity
public class Product {
private Long id;
private LocalString description;
private LocalString note;
@Embedded
public LocalString getDescription() {
return description;
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切正常:hbm2ddl ant任务创建了两个表,一个"Products"表和一个"Products_localStrings"表,其中包含键和值列.当我为第二个属性添加getter时,一切都会中断:
@Embedded
public LocalString getNote() {
return note;
}
Run Code Online (Sandbox Code Playgroud)
第二个属性未显示在架构中.我尝试使用@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;
}
Run Code Online (Sandbox Code Playgroud)
在生成的模式中,键列已消失,主键使用"description",这是不正确的:
create table Product_localStrings (Product_id bigint not null, note varchar(255), description varchar(255), primary key (Product_id, description));
Run Code Online (Sandbox Code Playgroud)
有任何解决这个问题的方法吗?
没有嵌入式组件,使用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>
Run Code Online (Sandbox Code Playgroud)
架构是
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);
Run Code Online (Sandbox Code Playgroud)
日志:
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'
Run Code Online (Sandbox Code Playgroud)
我如何告诉hibernate生成如下所示的单个插入?
insert into libro_strings (ID, idx, descrizione, giudizio) values (?, ?, ?, ?)
Run Code Online (Sandbox Code Playgroud)
编辑于2011.Apr.05
我一直在使用Map解决方案(使用@ElementCollection注释),直到我偶然发现了两个问题:
我知道有很多变通办法,比如使用HQL代替Criteria并定义自己的FieldBridge来处理Lucene中的Map,但我不喜欢变通方法:它们一直有效,直到下一个问题出现.所以我现在正在遵循这种方法:
我定义了一个保存语言环境和值的类"LocalString"(Locale实际上是ISO3代码):
@MappedSuperclass
public class LocalString {
private long id;
private String localeCode;
private String value;
Run Code Online (Sandbox Code Playgroud)
然后我为我想要本地化的每个属性定义一个LocalString的子类,它是空的:
@Entity
public class ProductName extends LocalString {
// Just a placeholder to name the table
}
Run Code Online (Sandbox Code Playgroud)
现在我可以在我的Product对象中使用它:
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;
}
Run Code Online (Sandbox Code Playgroud)
使用这种方法,我必须为我需要本地化的每个属性编写一个空类,这是为该属性创建唯一表所需的.好处是我可以无限制地使用Criteria和Search.
您的 xml 映射不起作用,因为您将值类型映射到同一个表中。当使用元素或复合元素时,数据被视为值类型并属于包含它的类。它需要自己的表。该 id 仅在集合中是唯一的。
要么将其映射为组件:
<component name="descrizioni">
<map name="localStrings" table="descrizioni_strings" ...>
<!-- ... -->
</map>
</component>
<component name="giudizi">
<map name="localStrings" table="giudizi_strings" ... >
<!-- ... -->
</map>
</component>
Run Code Online (Sandbox Code Playgroud)
或作为独立实体:
<many-to-one name="descrizioni" class="LocalString"/>
<many-to-one name="giudizi" class="LocalString"/>
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,LocalString 是一个实体。它需要一个 id 和它自己的映射定义。
归档时间: |
|
查看次数: |
3441 次 |
最近记录: |