我的问题是 this 的后续问题评论。
我在同一个类上混合使用 JPA 和 JAXB (MOXy) 注释,大多数情况下效果很好。如链接线程中所述,@XmlInverseReference
在编码双向关系时可防止循环异常。但为了检测循环,MOXy 必须检查链接实体的反向引用,如果需要填充惰性关系,这会导致额外的 SQL SELECT。
为了详细说明该问题,请考虑这个虚构的示例:
@Entity
@Access( AccessType.FIELD )
@XmlRootElement
@XmlAccessorType( XmlAccessType.FIELD )
public class Phone {
@ManyToOne
@JoinColumn( name = "employeeID" )
@XmlElement( name = "employee" )
@XmlInverseReference( mappedBy = "phones" )
private Employee employee;
private String number;
[...]
}
@Entity
@Access( AccessType.FIELD )
@XmlRootElement
@XmlAccessorType( XmlAccessType.FIELD )
public class Employee {
@OneToMany( mappedBy = "employee" )
@XmlElementWrapper( name = "phones" )
@XmlElement( name = "phone" )
@XmlInverseReference( mappedBy = "employee" )
private List<Phone> phones;
private String name;
[...]
}
现在,我将使用如下的 JAX-RS 方法在 Phone
上运行查询(使用底层 EJB):
@Inject
private PhoneService phoneService;
@GET
@Path( "/phones" )
public List<Phone> getPhonesByNumber( @QueryParam( "number" ) String number ) {
List<Phone> result = phoneService.getPhonesByNumber( number );
return result;
}
发生的情况是这样的:PhoneService
EJB 中的 JPQL 查询会触发 Phone
表上的 SQL SELECT(按号码过滤),并且如果我使用 JOIN FETCH
查询,我可以使用相同的单个 SELECT 语句获取关联的 Employee
。
当 JAX-RS 方法返回时,JAXB 编码启动,这会导致额外的 SQL SELECT:此选择选择其 employeeID
指向的所有 Phone
与最初请求的电话
关联的Employee
。因此,从 Employee
到 Phone
的惰性关系现在已经解决,大概是因为 MOXy 必须能够确定原始 Phone
是否包含在集合中.
我已尝试按照其他线程中的建议对 phones
字段使用 JPA 属性访问和 JAXB 字段访问,但无济于事。我还尝试在从 EJB 检索结果后(即当我的实体已分离时)将链接的 Employee 实例中的 Phones 字段清空,但这导致了再次立即执行 SQL SELECT(似乎只要对 IndirectList
进行任何操作,EclipseLink 就会执行此操作?)。我能找到的唯一解决方案是将 MOXy @XmlNamedObjectGraph
与排除 phones
字段的子图一起使用。但这是不切实际的,特别是当涉及的实体具有许多属性时。
因为我可能也需要向另一个方向查询,例如员工的姓名及其关联的电话,我不能只将电话
标记为@XmlTransient
。
有人有一个优雅的解决方案来抑制这些额外的 SQL 语句吗?
最佳答案
根据我的经验,完成您尝试的操作的最简单方法是在将所有实体类传递到 JAX-RS Rest api 等表示层之前分离它们。您甚至可以使用@OneToMany(mappedBy = "employee", cascade = CascadeType.DETACH)
和 EntityManager.detach()分离您的电话类别,然后分离您的员工类别,反之亦然。这将确保在编码实体期间,Jax-RS 不会触发您通常不需要的任何 SELECT 语句。
我总是在将模型实体传递到表示层之前分离它们,以便它们可以按照自己的意愿与模型类交互,而不会影响性能或数据库。
关于java - 如何避免使用 MOXy 加载惰性双向关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30163294/