举一个非常简单的一对多关系(国家/地区->)示例。
国家(反面):
@OneToMany(mappedBy = "country", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<StateTable> stateTableList=new ArrayList<StateTable>(0);
StateTable(拥有方):
@JoinColumn(name = "country_id", referencedColumnName = "country_id")
@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
private Country country;
尝试更新StateTable活动数据库事务(JTA 或本地资源)中提供的(分离的)实体的方法:
public StateTable update(StateTable stateTable) {
// Getting the original state entity from the database.
StateTable oldState = entityManager.find(StateTable.class, stateTable.getStateId());
// Get hold of the original country (with countryId = 67, for example).
Country oldCountry = oldState.getCountry();
// Getting a new country entity (with countryId = 68) supplied by the client application which is responsible for modifying the StateTable entity.
// Country has been changed from 67 to 68 in the StateTable entity using for example, a drop-down list.
Country newCountry = entityManager.find(Country.class, stateTable.getCountry().getCountryId());
// Attaching a managed instance to StateTable.
stateTable.setCountry(newCountry);
// Check whether the supplied country and the original country entities are equal.
// (Both not null and not equal - http://stackoverflow.com/a/31761967/1391249)
if (ObjectUtils.notEquals(newCountry, oldCountry)) {
// Remove the state entity from the inverse collection held by the original country entity.
oldCountry.remove(oldState);
// Add the state entity to the inverse collection held by the newly supplied country entity
newCountry.add(stateTable);
}
return entityManager.merge(stateTable);
}
需要注意的orphanRemoval是,设置为true。StateTable实体由有兴趣将实体关联Country( countryId = 67)更改StateTable为其他内容 ( )的客户端应用程序提供countryId = 68(因此在 JPA 的反面,将子实体从其父实体(集合)迁移到另一个父实体(集合)orphanRemoval=true反过来会反对)。
Hibernate 提供程序发出一个DELETEDML 语句,导致对应于StateTable实体的行从基础数据库表中删除。
尽管orphanRemoval设置为true,但我希望 Hibernate 发出一个常规的UPDATEDML 语句,导致 的效果orphanRemoval完全暂停,因为迁移了关系链接(而不是简单地删除)。
EclipseLink 正是完成了这项工作。它在给定的场景中发出一条语句(与set toUPDATE具有相同的关系)。orphanRemovaltrue
哪个符合规范?在这种情况下,除了从反面删除之外,是否可以让 Hibernate 发出UPDATE声明?orphanRemoval
这只是试图使双方的双向关系更加一致。
如有必要,上述代码段中使用的防御性链接管理方法在实体中add()定义如下。remove()Country
public void add(StateTable stateTable) {
List<StateTable> newStateTableList = getStateTableList();
if (!newStateTableList.contains(stateTable)) {
newStateTableList.add(stateTable);
}
if (stateTable.getCountry() != this) {
stateTable.setCountry(this);
}
}
public void remove(StateTable stateTable) {
List<StateTable> newStateTableList = getStateTableList();
if (newStateTableList.contains(stateTable)) {
newStateTableList.remove(stateTable);
}
}
更新 :
UPDATE如果给定的代码按以下方式修改,Hibernate 只能发出预期的DML 语句。
public StateTable update(StateTable stateTable) {
StateTable oldState = entityManager.find(StateTable.class, stateTable.getStateId());
Country oldCountry = oldState.getCountry();
// DELETE is issued, if getReference() is replaced by find().
Country newCountry = entityManager.getReference(Country.class, stateTable.getCountry().getCountryId());
// The following line is never expected as Country is already retrieved
// and assigned to oldCountry above.
// Thus, oldState.getCountry() is no longer an uninitialized proxy.
oldState.getCountry().hashCode(); // DELETE is issued, if removed.
stateTable.setCountry(newCountry);
if (ObjectUtils.notEquals(newCountry, oldCountry)) {
oldCountry.remove(oldState);
newCountry.add(stateTable);
}
return entityManager.merge(stateTable);
}
在较新版本的代码中观察以下两行。
// Previously it was EntityManager#find()
Country newCountry = entityManager.getReference(Country.class, stateTable.getCountry().getCountryId());
// Previously it was absent.
oldState.getCountry().hashCode();
如果最后一行不存在或被EntityManager#getReference()替换EntityManager#find(),则DELETE意外发出 DML 语句。
那么,这里发生了什么?特别是,我强调便携性。不跨不同的 JPA 提供者移植这种基本功能会严重破坏 ORM 框架的使用。
EntityManager#getReference()我了解和之间的基本区别EntityManager#find()。