I'm using Hibernate in many projets. Since time I've developped my projects including a translation table that containts text values in every language for every other tables that need it.
我在许多项目中使用Hibernate。从那时起,我开发了我的项目,包括一个转换表,其中包含每种语言的文本值,以及其他需要它的表。
Mapping file for the translation table
映射转换表的文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="com.spectotechnologies.website.common.helper.TranslationValue" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="common_translations">
<id name="keyTranslation">
<generator class="native"/>
</id>
<property name="keyLanguage"/>
<property name="tableName"/>
<property name="fieldName"/>
<property name="keyRow"/>
<property name="value"/>
</class>
</hibernate-mapping>
Exemple of one object that need translation :
一个需要翻译的对象的例子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="com.spectotechnologies.website.common.helper.Category" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="common_categories">
<id name="keyCategory">
<generator class="native"/>
</id>
<property name="keyParent"/>
<property name="tag"/>
<property name="name" insert="false" update="false"/>
<property name="description" insert="false" update="false"/>
</class>
</hibernate-mapping>
Currently, I use this kind of SQL query to load objects
目前,我使用这种SQL查询来加载对象
"SELECT" +
" c.keyCategory," +
" c.keyParent," +
" c.tag," +
" tn.value AS name," +
" td.value AS description" +
" FROM common_categories c" +
// name
" LEFT JOIN common_translations tn" +
" ON tn.tableName = 'common_categories'" +
" AND tn.fieldName = 'name'" +
" AND tn.keyRow = c.keyCategory" +
" AND tn.keyLanguage = ?" +
// description
" LEFT JOIN common_translations td" +
" ON td.tableName = 'common_categories'" +
" AND td.fieldName = 'description'" +
" AND td.keyRow = c.keyCategory" +
" AND td.keyLanguage = ?" +
" ORDER BY" +
" c.keyCategory ASC"
I was wondering if it is possible to transfer this kind of LEFT JOINS inside the mapping, for that I need to include parameters : tableName, fieldName, language.
我想知道是否有可能在映射中传输这种LEFT JOINS,因为我需要包含参数:tableName,fieldName,language。
Your help about that will be much appreciated, I'll be able to simplify a lot of queries!
非常感谢您对此的帮助,我将能够简化大量查询!
EDIT :
Here is an example of what I expect :
这是我期望的一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="com.spectotechnologies.website.common.helper.Category" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="common_categories">
<id name="keyCategory">
<generator class="native"/>
</id>
<property name="keyParent"/>
<property name="tag"/>
<one-to-many class="com.spectotechnologies.website.common.helper.TranslationValue"
formula="tableName = 'common_categories' AND fieldName = 'name' AND keyLanguage = @language AND keyRow = keyCategory" name="name" />
<one-to-many class="com.spectotechnologies.website.common.helper.TranslationValue"
formula="tableName = 'common_categories' AND fieldName = 'description' AND keyLanguage = @language AND keyRow = keyCategory" name="description" />
</class>
</hibernate-mapping>
In that case I would need to create a variable @language that could be injected at query time. There is two problems with this solution :
在这种情况下,我需要创建一个可以在查询时注入的变量@language。此解决方案存在两个问题:
-
I don't know if it is possible to publish a variable to mapping scope.
我不知道是否可以将变量发布到映射范围。
-
The formula is not existing for the moment : https://hibernate.onjira.com/browse/HHH-944
该公式暂时不存在:https://hibernate.onjira.com/browse/HHH-944
2 个解决方案
#1
0
For me all you need is to define one-to-many and many-to-one relation between the 2 entities. E.g. each category should have list (or set) of translations.
对我而言,您只需要定义2个实体之间的一对多和多对一关系。例如。每个类别都应该有翻译列表(或集合)。
#2
0
Since it was complicated to work with a table using a "custom key" (tableName and fieldName), I inverted the key. Now the Object needing multilingual text have a foreign key to the needed text. It only needs two tables for all multilingual data :
由于使用“自定义键”(tableName和fieldName)处理表很复杂,因此我将键反转。现在,需要多语言文本的对象具有所需文本的外键。所有多语言数据只需要两个表:
CREATE TABLE `common_multilingualtexts` (
`keyMultilingualText` int(11) NOT NULL auto_increment,
PRIMARY KEY (`keyMultilingualText`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
CREATE TABLE `common_multilingualtexts_values` (
`languageCode` varchar(5) NOT NULL,
`keyMultilingualText` int(11) NOT NULL,
`value` text,
PRIMARY KEY (`languageCode`,`keyMultilingualText`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
The MultilingualText is now like this :
MultilingualText现在是这样的:
@Entity
@Table(name = "common_multilingualtexts")
public class MultilingualText implements Serializable
{
private Integer m_iKeyMultilingualText;
private Map<String, String> m_lValues = new HashMap<String, String>();
public void setKeyMultilingualText(Integer p_iKeyMultilingualText)
{
m_iKeyMultilingualText = p_iKeyMultilingualText;
}
@Id
@GeneratedValue
@Column(name = "keyMultilingualText")
public Integer getKeyMultilingualText()
{
return m_iKeyMultilingualText;
}
public void setValues(Map<String, String> p_lValues)
{
m_lValues = p_lValues;
}
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "languageCode")
@CollectionTable(name = "common_multilingualtexts_values", joinColumns = @JoinColumn(name = "keyMultilingualText"))
@Column(name = "value")
public Map<String, String> getValues()
{
return m_lValues;
}
public void put(String p_sLanguageCode, String p_sValue)
{
m_lValues.put(p_sLanguageCode,p_sValue);
}
public String get(String p_sLanguageCode)
{
if(m_lValues.containsKey(p_sLanguageCode))
{
return m_lValues.get(p_sLanguageCode);
}
return null;
}
}
And each field that need to be multilingual simply need to be declared as follow :
每个需要多语言的字段只需要声明如下:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "keyTitle")
public MultilingualText getTitle()
{
return m_oTitle;
}
Note :
The only drawback is that each multilingual field generate a N + 1 select, I'll update my answer once I find a solution for that.
唯一的缺点是每个多语言字段都会产生N + 1选择,一旦找到解决方案,我就会更新我的答案。
#1
0
For me all you need is to define one-to-many and many-to-one relation between the 2 entities. E.g. each category should have list (or set) of translations.
对我而言,您只需要定义2个实体之间的一对多和多对一关系。例如。每个类别都应该有翻译列表(或集合)。
#2
0
Since it was complicated to work with a table using a "custom key" (tableName and fieldName), I inverted the key. Now the Object needing multilingual text have a foreign key to the needed text. It only needs two tables for all multilingual data :
由于使用“自定义键”(tableName和fieldName)处理表很复杂,因此我将键反转。现在,需要多语言文本的对象具有所需文本的外键。所有多语言数据只需要两个表:
CREATE TABLE `common_multilingualtexts` (
`keyMultilingualText` int(11) NOT NULL auto_increment,
PRIMARY KEY (`keyMultilingualText`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
CREATE TABLE `common_multilingualtexts_values` (
`languageCode` varchar(5) NOT NULL,
`keyMultilingualText` int(11) NOT NULL,
`value` text,
PRIMARY KEY (`languageCode`,`keyMultilingualText`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
The MultilingualText is now like this :
MultilingualText现在是这样的:
@Entity
@Table(name = "common_multilingualtexts")
public class MultilingualText implements Serializable
{
private Integer m_iKeyMultilingualText;
private Map<String, String> m_lValues = new HashMap<String, String>();
public void setKeyMultilingualText(Integer p_iKeyMultilingualText)
{
m_iKeyMultilingualText = p_iKeyMultilingualText;
}
@Id
@GeneratedValue
@Column(name = "keyMultilingualText")
public Integer getKeyMultilingualText()
{
return m_iKeyMultilingualText;
}
public void setValues(Map<String, String> p_lValues)
{
m_lValues = p_lValues;
}
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "languageCode")
@CollectionTable(name = "common_multilingualtexts_values", joinColumns = @JoinColumn(name = "keyMultilingualText"))
@Column(name = "value")
public Map<String, String> getValues()
{
return m_lValues;
}
public void put(String p_sLanguageCode, String p_sValue)
{
m_lValues.put(p_sLanguageCode,p_sValue);
}
public String get(String p_sLanguageCode)
{
if(m_lValues.containsKey(p_sLanguageCode))
{
return m_lValues.get(p_sLanguageCode);
}
return null;
}
}
And each field that need to be multilingual simply need to be declared as follow :
每个需要多语言的字段只需要声明如下:
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "keyTitle")
public MultilingualText getTitle()
{
return m_oTitle;
}
Note :
The only drawback is that each multilingual field generate a N + 1 select, I'll update my answer once I find a solution for that.
唯一的缺点是每个多语言字段都会产生N + 1选择,一旦找到解决方案,我就会更新我的答案。