Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa 带自联接表的SqlResultsMapping_Jpa_Entity_Orm - Fatal编程技术网

Jpa 带自联接表的SqlResultsMapping

Jpa 带自联接表的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")

我有一个自联接的查询,如下所示

选择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")
使用以下结果集映射

@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 ...)