Jpa 带自联接表的SqlResultsMapping
我有一个自联接的查询,如下所示 选择t1,t2。来自表t1 t2.LFTJpa 带自联接表的SqlResultsMapping,jpa,entity,orm,Jpa,Entity,Orm,我有一个自联接的查询,如下所示 选择t1,t2。来自表t1 t2.LFTt1.RGT t2.REG_CODE_PAR='ALL' 和t1.STATUS_CODE='A' 和t2.STATUS_CODE='A' 我使用带有结果集映射的@NamedNativeQuery来获得结果 @NamedNativeQuery( name="findTree", query="..... the query above", resultSetMapping = "regionT")
@NamedNativeQuery(
name="findTree",
query="..... the query above",
resultSetMapping = "regionT")
使用以下结果集映射
@SqlResultSetMapping(name = "regionT" , entities ={
@EntityResult(
entityClass = Tree.class
fields = {
@FieldResult(name = "regCode", column = "REG_CODE")
@FieldResult(name = "rgt", column = "RGT"),
@FieldResult(name = "lft", column = "LFT"),
@FieldResult(name = "name", column = "NAME"),
@FieldResult(name = "regCodePar", column = "REG_CODE_PAR"),
@FieldResult(name = "statusCode", column = "STATUS_CODE")
}
),
@EntityResult(
entityClass = TreeSelf.class
fields = {
@FieldResult(name = "regCode1", column = "REG_CODE")
@FieldResult(name = "rgt1", column = "RGT"),
@FieldResult(name = "lft1", column = "LFT"),
@FieldResult(name = "name1", column = "NAME"),
@FieldResult(name = "regCodePar1", column = "REG_CODE_PAR"),
@FieldResult(name = "statusCode1", column = "STATUS_CODE")
}
)
})
entity类包含如下内容
@NamedNativeQuery(...)
@SqlResultSetMapping(...)
@Entity
@Table(name = "table")
public class Tree implements Serializable {
@Id
@Column(name = "REG_CODE")
private String regCode; ... ..getters and setters...}
当我使用em.createQuery(“findTree”)运行查询时,我在这两个数据库中得到了完全相同的对象
返回的对象数组的第一个和第二个元素。
即使我创建了一个名为TreeSelf的类,该类与Tree相同,并将其用作第二个类
EntityResult使用相同的entityClass生成两个EntityResult,而不是相同的EntityResult
结果
有人能指出配置有什么问题吗?让我们看看我是否理解您的问题。您希望从每个本机查询结果行捕获两个
树
实体。第一个实体应该由t1
的列组成。第二个实体应由t2
的列组成。与预期相反,您实际上收到了由t1
构成的两个实例。没有出现来自t2
的实例。您在调试时为Tree
创建了名为TreeSelf
的doppelganger实体,但TreeSelf
最终是不必要的,您希望将其删除。如果有任何错误,请阻止我
我认为问题是由于不明确的列名造成的。本机查询中的每个列名显示两次,一次来自t1
,一次来自t2
。结果映射器似乎在为两个树
实体任意选择每个不明确列名的第一个匹配项。我很惊讶这能奏效。我原以为会出现SQLException,抱怨列引用不明确
另外,您确定要左外联接吗?如果未找到t1
行的匹配项,该怎么办?它将与t2
列中的所有空值配对。然后您有一个空值树
实体。我想。我甚至不知道结果映射器在这种情况下会做什么。也许你想要一个内部连接
考虑将此本机查询转换为JPQL查询。(JPA Criteria API也一样,但我发现它对于示例来说更麻烦。)以下是本机查询的JPQL版本:
SELECT t1, t2
FROM Tree t1, Tree t2
WHERE t2.lft < t1.lft AND t2.rgt > t1.rgt AND t2.regCodePar = 'ALL' AND
t1.statusCode = 'A' AND t2.statusCode = 'A'
每个字段结果中的列
属性必须相应更改。因此,第一个EntityResult
下的列
属性都应该以t1\u
开头,第二个属性都应该以t2\u
开头
我谦虚地建议您删除本机查询和sql结果映射器,并使用JPA查询语言或条件API(如果您能找到方法的话)
更新:正如您在评论中确认的,对您的问题的有用答案必须保留左(外部)连接语义。不幸的是,JPQL和CriteriaAPI不支持复杂的左连接条件。无法使用显式的ON
条件限定JPQL左连接
据我所知,在规范下进行左外连接的唯一方法是遍历实体关系。然后,JPA实现在
条件上生成一个测试身份平等性的。相关规范位为4.4.5“连接”和4.4.5.2“左外连接”
要满足此约束,每个要左键连接到其最终父级的树必须有一个额外的列来存储最终父级的id。您可以通过多种方式(视图?)绕过此约束。但阻力最小的途径似乎是修改本机查询以使用别名参数,删除TreeSelf,并相应地更新结果映射器。欢迎使用更聪明的解决方案,不过…您是想打印选择t1.*,t2.*
而不是选择t1.,t2.
?看起来格式化程序把你绊倒了。嗨,丹,谢谢你的洞察力。是的,你正确理解了我的问题,但让我告诉你一些历史。这是系统中现有的查询。我的目标是将其转换为JPA Criteria API,但由于左连接上的多个条件而遇到问题(是的,左连接是必需的。空情况在应用程序中处理)。我在这里发布了这个问题:JPQL面临的另一个问题是树数据结构是表中的层次结构。每行都有一列(parent_id),该列引用表中另一行的主键。通过执行@ManyToOne@JoinColumn(name=“parent\u id”)私有树;我会得到它的直系父母。本机查询中t2的结果实际上返回顶级父记录,而不是直接父记录。使用JPQL,我必须将.getTree().getTree().getTree()..…getTree()树分为6或7个级别才能获得顶级父级。所有这些,如果多条件联接和顶级父级问题可以解决,我的首选是使用JPA标准。如果你有什么意见,我很想听听。Thanks@Jonathan-感谢您澄清并链接到相关问题。据我所知,在JPQL或Criteria API中,如果不以某种方式修改实体和/或支持数据库对象,就很难实现这种左连接。我在答案的末尾添加了一个详细的更新。谢谢你的回复。非常感谢。我已经看过说明书了。只是想知道是否有人有一个优雅的解决方案
EntityManager em = ... // EntityManager by injection, EntityManagerFactory, etc.
String jpql = ... // Like example above
TypedQuery<Object[]> q = em.createQuery(jpql, Object[].class);
for (Object[] oa : q.getResultList()) {
Tree t1 = (Tree)oa[0];
Tree t2 = (Tree)oa[1];
}
SELECT t1.REG_CODE AS t1_REG_CODE, t1.RGT AS t1_RGT, (... rest of t1 cols ...),
t2.REG_CODE AS t2_REG_CODE, t2.RGT AS t2_RGT, (... rest of t2 cols ...)