gpt4 book ai didi

hibernate - 在Hibernate中映射本地化的字符串-有什么最佳实践吗?

转载 作者:行者123 更新时间:2023-12-04 08:53:30 25 4
gpt4 key购买 nike

我正在编写一个必须将所有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”表和一个包含键和值列的“Products_localStrings”表。
当我为第二个属性添加 setter/getter 时,一切都会中断:
   @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注释)已有一段时间,直到我偶然发现了两个问题:
  • 当前的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代替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及其自己的映射定义。

    关于hibernate - 在Hibernate中映射本地化的字符串-有什么最佳实践吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4784718/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com