[英]How to properly implement a owner-owned-owner2 association in java with hibernate?
I have looked for information on how to implement the following association in hibernate and although the hibernate manual is very thorough, I haven't found the following use case addressed. 我已经查找了有关如何在hibernate中实现以下关联的信息,虽然hibernate手册非常彻底,但我还没有找到以下用例。
I have a requirement to have an association between to entities, where the association has several attributes besides the foreign keys to the associated entities. 我要求在实体之间建立关联,其中关联除了关联实体的外键之外还有几个属性。 The specifications for the relation are:
关系的规范是:
I have managed to configure most of the requirements through annotations and it works out quite nicely, except for cascading the delete from the Contained item. 我已经设法通过注释配置了大部分需求,并且它很好地工作,除了从Contained项目级联删除。 I have a work around to do this described below, but I would like to configure this action through annotations to have the database automatically do the work in order to have a more robust referential integrity.
我有一个工作要做,如下所述,但我想通过注释配置此操作,让数据库自动完成工作,以便具有更强大的参照完整性。
This is the mapping that I have so far: 这是我到目前为止的映射:
@Entity
public class Container
{
@OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER)
@JoinColumn(name = "container_fk")
public Set<Position> getPositions() { return this.positions; }
public void setPositions(final Set<Position> positions) { this.positions = positions; }
private Set<Position> positions;
...
}
@Entity
public class Position
{
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "container_fk", insertable = false, updatable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
public Container getContainer() { return this.container; }
public void setContainer(Container container) { this.container = container; }
private Container container;
@NaturalId
@OneToOne(optional = false, fetch = FetchType.EAGER)
@JoinColumn(name = "contained_fk")
public Contained getContained() { return this.contained; }
public void setContained(Contained contained) { this.contained = contained; }
private Contained contained;
// other attributes are owned by this relationship
// (i.e., they don't make sense in either Container or Contained.
...
}
To delete the Position, when deleting the Contained item the following is implemented in code in a ContainedDao (presented without exception handling and session management is done in the base Dao class for simplicity): 要删除位置,在删除Contained项时,以下内容在ContainedDao中的代码中实现(无异常处理,并且为了简单起见,在基本Dao类中进行了会话管理):
@Repository
@Transactional(rollbackFor = Throwable.class)
public class ContainedDao extends TransactionalDao<Contained>
{
public void delete(String id)
{
final Session session = getSession();
// If there is a Position associated to the Contained item delete it,
// and remove it from any Container collection.
Position position = (Position) session.createCriteria(Position.class)
.createCriteria("contained")
.add(Restrictions.eq("id", id))
.uniqueResult();
if (position != null)
{
position.getContainer().getPositions().remove(position);
session.delete(position);
}
// Delete the Contained item.
Contained object = session.load(Contained.class, id);
session.delete(contained);
}
}
What I would like to do is to somehow configure through annotations so that the ContainedDao.delete method is simplified to a simple: 我想做的是以某种方式通过注释进行配置,以便将ContainedDao.delete方法简化为一个简单的方法:
// Delete the Contained item.
Contained object = session.load(Contained.class, id);
session.delete(contained);
Is this possible? 这可能吗? Or is my current solution the best I can get?
或者我现在的解决方案是我能得到的最好的解决方 Is there a better way to approach this?
有没有更好的方法来解决这个问题? Note that a key factor here is that Position containes additional attributes;
请注意,这里的关键因素是Position包含其他属性; otherwise, I would have configured the association between Container/Contained directly and let hibernate manage the association.
否则,我会直接配置Container / Contained之间的关联,让hibernate管理关联。
When you say "A Position refers to one and only one Contained item" , do you mean a one-to-one relationship (as opposed to a many-to-one )? 当你说“的位置指的是一个和唯一一个包含的项目”,你的意思是一比一的关系(而不是多到一 )? If that is the case, then I suppose what you really want to express here is that Position is-a Contained entity.
如果是这种情况,那么我想你真正想要表达的是Position 是一个包含的实体。
The single difference between a one-to-one and an is-a relationship is in the life-cycle of the relationship. 一对一的和之间的单差是-的关系是在关系的生命周期。 In a one-to-one relationship the Contained instance to which the Position points to might change.
在一对一关系中,Position指向的Contained实例可能会更改。 An is-a relationship is more restricted: the relationship is essentially the identity of the Position itself, therefore changing it is not allowed.
is-a关系受到更多限制:关系本质上是Position本身的身份,因此不允许更改它。
To implement an is-a relationship you need three things: 要实现is-a关系,您需要三件事:
Then following DAO code to delete a Contained instance would also cascade to Position: 然后按照DAO代码删除一个Contained实例也会级联到Position:
public void deleteContained(String id)
{
Contained c = (Contained) session.createCriteria(Contained.class)
.add(Restrictions.eq("id", id))
.uniqueResult();
// Removes associated Position too, if exists
session.delete(c);
// This would fail now:
// session.load(Position.class, id);
}
Also, deleting a Position instance would cascade to Contained: 此外,删除Position实例将级联为Contained:
public void deletePosition(String id)
{
Position p = (Position) session.createCriteria(Position.class)
.add(Restrictions.eq("id", id))
.uniqueResult();
// Removes associated Contained too
session.delete(p);
// This would fail now:
// session.load(Contained.class, id);
}
PS A one-to-one relationship is a bogus concept anyway, an OOP illusion. PS无论如何,一对一的关系是一种虚假的概念,一种OOP错觉。 Instead of using a one-to-one, such relationships should either be properly restricted to an is-a , or reconsidered as a many-to-one .
这种关系应该被适当地限制为is-a ,或者被重新考虑为多对一 ,而不是一对一使用 。 You can substitute most of my points about one-to-one with many-to-one above.
你可以用上面的多对一替换大多数关于一对一的点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.