struts2+hibernate采用annotation进行ManyToOne关联的问题

struts2+hibernate,有实体类User(用户)、Gender(性别),做字典字段的ManyToOne关联,如下:

用户类
[code="java"]
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name = "TB_User")
public class User{
Long id; //用户主键
String userName; //姓名
Gender gender; //性别

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

// 多对一定义
@ManyToOne(optional = true, fetch = FetchType.EAGER)
@JoinColumn(name = "gender", referencedColumnName = "itemId")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public Gender getGender() {
return gender;
}

public void setGender(Gender gender) {
this.gender = gender;
}
}
[/code]

性别类
[code]
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity
@Table(name = "TB_DICT")
public class Gender implements Serializable {
Long id; //字典主键
Long dictId; //字典类型编号:1表示性别
Long dictName; //字典类型名称
Long itemId; //项目编号 1:男 2:女
String itemName;//项目名称

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getDictId() {
return dictId;
}
public void setDictId(Long dictId) {
this.dictId = dictId;
}
public String getDictName() {
return dictName;
}
public void setDictName(String dictName) {
this.dictName = dictName;
}
public Long getItemId() {
return itemId;
}
public void setItemId(Long itemId) {
this.itemId = itemId;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
}
[/code]

页面:
[code="html"]

$().ready(function(){ $("#gender").val('${gender.itemId}')//设置下拉框默认值 }

编号:


用户名:


性别:




[/code]

在页面上用alert('${gender.itemName}')可正确显示当前记录的“性别”中文名称,可见关联关系是建立起来了。但在将某记录的性别从“男”修改为“女”,并保存(执行getSession().saveOrUpdate(user))时,发生如下错误:
org.springframework.orm.hibernate3.HibernateSystemException: [color=red]identifier of an instance of accountant.entity.Gender was altered from 3 to 2[/color];

从错误提示看,hibernate尝试更新gender的ID字段,而主键是不允许更新的,因此出错

这里有两个问题:
(1)建立关联只为了查询字典字段的中文名称,更新时只想更新TB_User的gender字段,而不是更新TB_DICT的值,这要如何设置?(是设置cascade参数吗?但CascadeType中似乎没有“NONE”一项)
(2)这里提示的“altered from 3 to 2”,3是“男”的id值,2是“女”的item_id值。既然已经设置了referencedColumnName = "itemId",即使要更新TB_DICT的值也应该更新的是item_Id字段,为什么实际会去更新id字段?
id dict_id dict_name item_id item_name
3 1 性别 1 男
4 1 性别 2 女

不得其解,请大家帮忙

2个回答

哥们你的多对一配置有问题
-----User
private Long id;
private String userName;
private Set genders;

----Gender
private Long id; //字典主键

private Long dictId; //字典类型编号:1表示性别

private Long dictName; //字典类型名称

private Long itemId;//项目编号 1:男 2:女

private String itemName;//项目名称

private User user;
多对一User多对 Gender。一个用户可以参加多个Gender
User 类中的 private Set genders;
类型的可以换成
private List genders;
希望能帮上忙

weixin_42318113
weixin_42318113 主要问题没解决,不过分还是给你吧
7 年多之前 回复
weixin_42318113
weixin_42318113 试过了,不起作用啊,还是会去修改tb_dict。甚至试过配成CascadeType.REMOVE,这应该是只有删除的时候才应该更新关联表吧,可修改的时候还是会更新tb_dict。有什么情况会导致cascade的设置无效吗?
7 年多之前 回复
iteye_5246
iteye_5246 @ManyToOne(cascade={CascadeType.MERGE,CascadeType.REFRESH},optional=true)
7 年多之前 回复
weixin_42318113
weixin_42318113 谢谢,改成<select id="gender" name="gender.itemId">后确实会更新itemId,问题2解决了。问题1不知道有没有办法?字典字段应该是很常见的,不知道这类问题平时是怎么处理的?
7 年多之前 回复
iteye_5246
iteye_5246 <select id="gender" name="gender.id"> 这样传到后台 不更新id更新什么 应该<select id="gender" name="gender.itemId">
7 年多之前 回复
weixin_42318113
weixin_42318113 我的问题是 1、配置关联后,更新时如何只更新用户表,不更新字典表 2、关联关系中已经指定了referencedColumnName,为什么还会去更新默认的id字段
7 年多之前 回复
iteye_5246
iteye_5246 ...那问题什么意思[ManyToOne关联的问题]一对一更好办了。 把@ManyToOne(optional = true, fetch = FetchType.EAGER)改为 @OneToOne(optional = true, fetch = FetchType.EAGER) @JoinColumn(name = "gender", referencedColumnName = "itemId") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public Gender getGender() { return gender; }
7 年多之前 回复
weixin_42318113
weixin_42318113 谢谢关注,但似乎不是这个问题吧: 一个用户只能有一个性别,多个用户可对应同一个性别,所以才多对一 一个用户对应多个性别,那是一对多了
7 年多之前 回复

-----User
private Long id;
private String userName;
private Set genders;

@ManyToOne(optional = true, fetch = FetchType.EAGER)

@JoinColumn(name = "gender", referencedColumnName = "itemId")

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

private Gender genders;

----Gender
private Long id; //字典主键
private Long dictId; //字典类型编号:1表示性别
private Long dictName; //字典类型名称
private Long itemId;//项目编号 1:男 2:女
private String itemName;//项目名称

@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
@JoinColumn(name = "???")
private List users;

weixin_42318113
weixin_42318113 试过了,把关联配在属性而不是方法上会报错: org.hibernate.type.SerializationException: could not deserialize at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:188) at org.hibernate.util.SerializationHelper.deserialize(SerializationHelper.java:211) at org.hibernate.type.SerializableType.fromBytes(SerializableType.java:105) at org.hibernate.type.SerializableType.get(SerializableType.java:62) at org.hibernate.type.NullableType.nullSafeGet(NullableType.java:184) 当然正常应该是可以配在属性上的,不知道哪里没搞对。 不过这个不是目前我的主要问题,先不去管他 给出的代码中,在ONE段配置了CascadeType.ALL,这个的作用应该是One段修改后自动更新Many端吧?我现在的问题是,如何在Many对象修改时只修改本身,不要去修改关联的ONE端。CascadeType中没有“NONE”,难道只要建立了关联关系必须要强制更新被关联方吗?
7 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!