举一个非常简单的一对多关系(国家/地区->
)示例。
国家(反面):
@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 提供程序发出一个DELETE
DML 语句,导致对应于StateTable
实体的行从基础数据库表中删除。
尽管orphanRemoval
设置为true
,但我希望 Hibernate 发出一个常规的UPDATE
DML 语句,导致 的效果orphanRemoval
完全暂停,因为迁移了关系链接(而不是简单地删除)。
EclipseLink 正是完成了这项工作。它在给定的场景中发出一条语句(与set toUPDATE
具有相同的关系)。orphanRemoval
true
哪个符合规范?在这种情况下,除了从反面删除之外,是否可以让 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()
。