JPA/Hibernate中的条件/组合JoinColumn

3

在我的某个课程中,比如位置(Location),我有这样一个东西:

private List<Magician> magicians;

...

@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name="location_id")
public List<Magician> getMagicians() {
    return magicians;
} 

public void setMagicians(List<Magician> magicians) {
    this.magicians = magicians;
}

Magician有变量的地方

private Integer id;
private Integer location_id;
private Boolean active;

现在我想修改getter注释,以便仅获取活动为真的魔术师。如何实现?谢谢关注。

感谢JB和Kevin的回答。我提出问题的动机是,有些情况下我可能希望限制应用程序访问的数据集,而不引入代码中的任何新方法。因此,我会通过使用数据库查询将active设置为true来快速准备数据。 - Andrea Alciato
3个回答

2
首先,Magician 不应该有一个 location_id 字段。它应该有一个类型为 Location 的字段。这将在两个实体之间建立双向关联:
@OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "location")
public List<Magician> getMagicians() {
    return magicians;
} 

...

@ManyToOne
@JoinColumn(name = "location_id")
public Location getLocation() {
    return this.location;
}

那么,回答你的问题,实体的状态和关联不用于实现特定的用例或查询。它们用于建模数据库包含的内容。要获取给定位置的活跃魔法师,你只需使用一个查询:

select m from Magician m where m.active = true and m.location = :location

感谢您的回复。关于单向与双向点的问题,我同意axtavt的评论(https://dev59.com/iW435IYBdhLWcg3wigkk#5361587):“导航访问并不总是好的,特别是对于‘一对很多’和‘很多对很多’的关系。”我认为除非必要,否则不应该使用双向,特别是在一个“一对很多”普遍存在的应用程序中,比如我的应用程序。我认为这是一个非常相关的问题,欢迎您提出任何进一步的评论,我们将不胜感激。 - Andrea Alciato
如果是一对多关系,那么将其建模为单向的ManyToOne关联可能有很好的理由。但你正在将其建模为单向的OneToMany关联。而且你在Magician中已经有了位置的ID(这使得你的映射不正确,因为该列被映射了两次),那么为什么不使用延迟加载的Location呢? - JB Nizet
因为位置是一个大对象,当我与魔术师一起工作时,我通常不需要它(或者我已经有了),而我通常只需要location_id。所以我只保留location_id。至于你的观察结果,如果关系是双向的,即如果我遵循你的建议(我很感激,如果我错了,请纠正我),那么它将被映射两次。 - Andrea Alciato
如果每个双向关联都导致映射错误,那么双向关联将不会非常有用。通过在Magician中将ID映射为基本列,并将其作为 Location 中 OneToMany 关联的连接列进行映射,您正在进行两次映射,这将导致映射异常。我认为您正在过早地进行优化。我会使用双向关联。通过ID获取位置应该非常快,即使它是一个大对象。如果您不需要位置,因为它是懒加载的,那么不会执行任何查询来加载它。 - JB Nizet
我的观点是,我经常需要location_id,我不想每次需要一个location_id时都加载一个臃肿的Location。目前还没有映射异常,已经过了一段时间了。顺便说一下,作为举例,魔术师可以是原子,位置可以是蛋白质。欢迎提出更多评论。附言:我的意思是,如果我按照你的建议并在Magician中保留location_id,则会被映射两次。我并不是说你的建议是错误的。 - Andrea Alciato

1
我不会在实体级别执行此工作,而是使用EntityManager创建查询来执行。正如JB所提到的,您需要将位置添加为一个复合对象,而不是一个整数。

//在方法中

List<Magician> magicians = 
   em.createQuery("select m from Location l join Magician m where m.active = true and
   l.[specify id here] = :locationId", Magician.class).setParameter("locationId",
   1).getResultList();

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接