@SQLResultSetMapping+Joins 在多个实体上的不同结果 | JPA

Different result for @SQLResultSetMapping+Joins on multiple entities | JPA

我正在使用 JPA 运行Ning NativeQuery,与 运行在 sql 工具中使用查询相比,它给出不同的结果。可能是我理解错了s.th。在@SQLResultSetMapping 的概念内。

--- 概述 ---

我正在将结果映射到两个实体,因此我希望收到一个实体对列表。这行得通。

当您查看下图时,您会在 sql 工具中看到查询结果,其中 ..

JPA 应该给我一个本机行作为一对两个实体。

问题

这就是问题所在。是的,我将收到两个实体对的列表,但与图片中不同的是,列 "pp.id" 不会遍历相应 table 的所有行(在图片“5,6,7, ..”,来自 JPA“5,5,5,5,..”)。

列 pp.id 是一个连接列,我想我在 JPA 中对连接 + SQLResultSetMappings 有误解。在我看来,不同之处在于 JPA 总是从 table 'propertyprofile' 加入同一行(下面有更多详细信息),这与 sql 中的查询 运行 不同。

希望有人可怜我,帮助我。 :)

--- 详情 ---

查询

我基本上是想知道是否每个 'product' 都为预定义的 'property' (table 定义了 'value' (table 属性值)属性配置文件)。

可能最相关的部分在底部,其中 "propertyprofile" 是连接的,"propertyvalue" 是左连接的。

select sg.ID as 'sg.id', sg.Name as 'sg.name', ppcount.totalppcount as 'sg.totalppcount', ppcount.totalppothercount as 'sg.totalppothercount',
p.ID as 'product.id', pp.id as 'pp.id', pp.Role as 'pp.role', pp.Name as 'pp.name',
(case when pv.id is null then '0' else '1' end) as 'hasPropertyValue', pv.ID as 'pv.id', pv.StringValue, pv.IntervallMin, pv.IntervallMax
from shoppingguide sg
join
(
    select sg.ID as 'sgid', count(*) as 'totalppcount', count(pp_other.ID) as 'totalppothercount' from propertyprofile pp_all
    left join propertyprofile pp_other on pp_other.id = pp_all.id AND pp_other.Role = '0'
    join shoppingguide sg on pp_all.ShoppingGuideID = sg.ID
    join shopifyshop ss on sg.ShopifyShopID = ss.ID
    where
    pp_all.ShoppingGuideID = sg.ID AND
    ss.Name = :shopName
    GROUP BY pp_all.ShoppingGuideID
) ppcount on ppcount.sgid = sg.id
join shopifyshop ss on sg.ShopifyShopID=ss.ID
join product p on p.ShopifyShopID = ss.ID
join propertyprofile pp on (pp.ShoppingGuideID = sg.id AND pp.Role = '0')
left join propertyvalue pv on (pv.ProductID=p.ID and pv.PropertyProfileID = pp.id)
where 
ss.Name = :shopName
order by sg.id asc, p.id asc, pp.id asc
;

表格

涉及很多 table,但这些是理解查询最重要的:

SQLResultSetMapping

映射到两个实体:ProductDataFillSummary_ShoppingGuideInformation、ProductDataFillSummary_ProductInformation。

@SqlResultSetMapping(
        name = "ProductDataFillSummaryMapping",
        entities = {
            @EntityResult (
                    entityClass = ProductDataFillSummary_ShoppingGuideInformation.class,
                    fields = {
                        @FieldResult(name = "shoppingGuideId", column = "sg.id"),
                        @FieldResult(name = "shoppingGuideName", column = "sg.name"),
                        @FieldResult(name = "numberOfTotalPropertyProfiles", column = "sg.totalppcount"),
                        @FieldResult(name = "numberOfTotalPropertyProfilesOther", column = "sg.totalppothercount")
                    }),
            @EntityResult(
                    entityClass = ProductDataFillSummary_ProductInformation.class,
                    fields = {
                        @FieldResult(name = "productID", column = "product.id"),
                        @FieldResult(name = "propertyProfileId", column = "pp.id"),
                        @FieldResult(name = "propertyProfileRole", column = "pp.role"),
                        @FieldResult(name = "propertyValueId", column = "pv.id"),
                        @FieldResult(name = "hasPropertyValue", column = "hasPropertyValue")
                        }
                    )
        })

分析

问题似乎是 Hibernate 没有 ..

  • .. 处理每一行
  • .. 每行映射到指定实体
  • .. 将此行的映射实体放入列表(在我的示例中是一对实体)

事实上,hibernate 似乎匹配两个实体,它们应该根据主键属性进入列表的相同条目,即像这样的东西:

  • .. 处理每一行
  • .. 对于每个行映射到各自的实体(分别)
  • .. 使用主键存储映射实体
  • .. 匹配进入 List
  • 相同条目的各个实体

在我的示例中,一对 [ProductDataFillSummary_ShoppingGuideInformation, ProductDataFillSummary_ProductInformation] 将被插入到列表中。当插入 'ProductDataFillSummary_ProductInformation' 时,Hibernate 将尝试使用主键(这里是 'ProductDataFillSummary_ProductInformation.productId')找到正确的实例。由于 ProductDataFillSummary_ProductInformation 的几行具有相同的 productId 值,因此始终会获取第一个实例并将其用于列表。

解决方案

要么使用考虑 'ProductDataFillSummary_ProductInformation.productId' 和“.propertyProfileId”的复合键,要么 ..

如果无法使用组合密钥,请使用人工密钥 (uuid):

concat(p.ID, '-', pp.ID) as 'uuid'