【发布时间】:2014-06-22 16:36:53
【问题描述】:
我发现当一对多关系中的父表更新时,子表上依赖数据的外键被设置为空,从而在子表上留下孤立记录。
我有两个用 Hibernate 标签注释的 Java 类。父表是:
@Entity
@Table(name = "PERSON")
public class Person implements Serializable {
// Attributes.
@Id
@Column(name="PERSON_ID", unique=true, nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer personId;
@Column(name="NAME", nullable=false, length=50)
private String name;
@Column(name="ADDRESS", nullable=false, length=100)
private String address;
@Column(name="TELEPHONE", nullable=false, length=10)
private String telephone;
@Column(name="EMAIL", nullable=false, length=50)
private String email;
@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="PERSON_ID")
private List<Book> books;
而子表是:
Entity
@Table(name = "BOOK")
public class Book implements Serializable {
// Attributes.
@Id
@Column(name="BOOK_ID", unique=true, nullable=false)
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer bookId;
@Column(name="AUTHOR", nullable=false, length=50)
private String author;
@Column(name="TITLE", nullable=false, length=50)
private String title;
@Column(name="DESCRIPTION", nullable=false, length=500)
private String description;
@Column(name="ONLOAN", nullable=false, length=5)
private String onLoan;
// @ManyToOne
// private Person person;
但是当对 Person 发出更新时,任何与父级相关的 Books 记录都设置为 null。
Book 表是:
CREATE TABLE BOOK (
BOOK_ID INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1),
AUTHOR VARCHAR(50) NOT NULL,
TITLE VARCHAR(100) NOT NULL,
DESCRIPTION VARCHAR(500) NOT NULL,
ONLOAN VARCHAR(5) NOT NULL,
PERSON_ID INTEGER,
CONSTRAINT PRIMARY_KEY_BOOK PRIMARY KEY(BOOK_ID),
CONSTRAINT FOREIGN_KEY_BOOK FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PERSON_ID))
而Person controller 中的update 方法是:
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(@ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
而实际DAO级别的方法是:
@Override
public void update(Person person) {
logger.info(PersonDAOImpl.class.getName() + ".update() method called.");
Session session = sessionFactory.openSession();
Transaction transaction = session.getTransaction();
try {
transaction.begin();
session.update(person);
transaction.commit();
}
catch(RuntimeException e) {
Utils.printStackTrace(e);
transaction.rollback();
throw e;
}
finally {
session.close();
}
}
所以我假设update 是问题的原因,但为什么呢?
我尝试过merge、persist 和saveOrUpdate 方法作为替代方法,但无济于事。
关于我的 Book 表没有 @ManyToOne 的注释这一事实,禁用此标记是我可以让 LAZY 获取工作的唯一方法。
这种情况似乎也与Hibernate one to many:"many" side record's foreign key is updated to null automatically 和Hibernate Many to one updating foreign key to null 非常相似,但是如果我将这些问题中对类指定的更改应用到我自己的表中,我的应用程序似乎甚至因为使用@ 的问题而拒绝编译987654337@ 在 Person 表中。
欢迎任何建议。
控制器方法改为:
// Validates and updates changes made by a Person on profile.jap
@RequestMapping(value = "/profile", method = RequestMethod.POST)
public String postProfile(@ModelAttribute("person") Person person,
BindingResult bindingResult,
Model model) {
logger.info(PersonController.class.getName() + ".postProfile() method called.");
// Validate Person.
personValidator.validate(person, bindingResult);
if (bindingResult.hasErrors()) {
return "view/profile";
}
else {
// Get current Person.
Person currPerson = personService.get(person.getPersonId());
// Set Books to updated Person.
person.setBooks(currPerson.getBooks());
personService.update(person);
model.addAttribute("person", person);
return "view/options";
}
}
而且它有效。
【问题讨论】:
标签: java sql hibernate one-to-many updates