我正在尝试使用Java / Spring MVC和Hibernate在我的Web应用程序中设置一个简单的EAV模式。我似乎无法弄清楚这种情况下hibernate XML设置背后的魔力。
我的数据库表“SETUP”有三列:
数据库组合键由 user_id |组成setup_item
这是Setup.java类:
public class Setup implements CommonFormElements, Serializable {
private Map data = new HashMap();
private String saveAction;
private Integer speciesNamingList;
private User user;
Logger log = LoggerFactory.getLogger(Setup.class);
public String getSaveAction() {
return saveAction;
}
public void setSaveAction(String action) {
this.saveAction = action;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getSpeciesNamingList() {
return speciesNamingList;
}
public void setSpeciesNamingList(Integer speciesNamingList) {
this.speciesNamingList = speciesNamingList;
}
public Map getData() {
return data;
}
public void setData(Map data) {
this.data = data;
}
}
我对Hibernate设置的问题是,我似乎无法弄清楚如何映射出一个外键和一个映射的键将构造表的复合键的事实...这是应该的缺乏使用Hibernate的经验。以下是我最初的尝试:
<composite-id>
<key-many-to-one foreign-key="id" name="user" column="user_id" class="Business.User">
<meta attribute="use-in-equals">true</meta>
</key-many-to-one>
</composite-id>
<map lazy="false" name="data" table="setup">
<key column="user_id" property-ref="user"/>
<composite-map-key class="Command.Setup">
<key-property name="data" column="setup_item" type="string"/>
</composite-map-key>
<element column="setup_value" not-null="true" type="string"/>
</map>
非常感谢任何有关如何正确映射此常见场景的见解!
答案 0 :(得分:2)
如您所示,您有不一致映射
你说Setup类定义了一个复合主键(注意我创建了一个复合主键类(SetupId - 参见下文),它必须实现Serializable和equals以及hashcode方法)
package ar.domain;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
public class Setup implements Serializable {
private SetupId setupId;
private User user;
private Map data= new HashMap();
public SetupId getSetupId() {
return setupId;
}
public void setSetupId(SetupId setupId) {
this.setupId = setupId;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Map getData() {
return data;
}
public void setData(Map data) {
this.data = data;
}
public static class SetupId implements Serializable {
private Integer userId;
private String setupItem;
public String getSetupItem() {
return setupItem;
}
public void setSetupItem(String setupItem) {
this.setupItem = setupItem;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
@Override
public boolean equals(Object o) {
if (o == null)
return false;
if (!(o instanceof SetupId))
return false;
final SetupId other = (SetupId) o;
if (!(getUserId().equals(other.getUserId())))
return false;
if (!(getSetupItem().equals(other.getSetupItem())))
return false;
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash = 11 * hash + (getUserId() != null ? getUserId().hashCode() : 0);
hash = 11 * hash + (getSetupItem() != null ? getSetupItem().hashCode() : 0);
return hash;
}
}
}
由于您的Setup类具有值Type的Map,因此在定义其关系时应定义其复合外键(请参阅关键元素)
<class name="ar.domain.Setup">
<composite-id name="setupId" class="ar.domain.Setup$SetupId">
<key-property name="setupItem" type="string" column="SETUP_ITEM"/>
<key-property name="userId" type="integer" column="USER_ID"/>
</composite-id>
<many-to-one name="user" class="ar.domain.User" column="USER_ID" insert="false" update="false"/>
<map name="data" table="DATA_TABLE">
<key>
<column name="SETUP_ITEM"/>
<column name="USER_ID"/>
</key>
<map-key column="USER_ID"/>
<element column="SETUP_VALUE" not-null="true" type="string"/>
</map>
</class>
同时,使用复合外键列作为映射键(USER_ID,对吗?),这是没有意义的。为什么?
除此之外,Hibernate 不支持复合主键的自动生成
假设这里是你的SETUP表
SETUP_ITEM USER_ID
0 1
0 2
你的DATA_TABLE
SETUP_ITEM USER_ID
0 1
无论您是否尝试以下
,会发生什么?Integer userId = 3;
String setupValue = "someValue";
setup.getData().put(userId, setupValue);
由于SETUP表未定义值为3的USER_ID,您将看到约束违规。
记住
当你有一个无法更新的(复合)主键时,无论如何都要避免使用它来改变依赖它的可变属性。否则,Hibernate会抱怨它。