0

我正在使用 JPA 运行 NativeQuery,与在 sql 工具中运行查询相比,它给出了不同的结果。可能我误会了…… 在@SQLResultSetMapping 的概念内。

- - 概述 - -

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

当你看下面的图片时,你会在一个 sql 工具中看到查询的结果,其中 ..

  • .. RED BOX 映射到一个实体
  • .. 绿框映射到第二个实体

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

问题

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

pp.id 列是一个连接列,我想当涉及到 Joins + SQLResultSetMappings 时,我误解了 JPA 中的一些内容。在我看来,不同之处在于 JPA 总是从表“propertyprofile”中加入同一行(下面有更多详细信息),这与在 sql 中运行查询不同。

我希望有人同情我并帮助我。:)

- - 细节 - -

询问

我基本上是想找出是否每个“产品”都为预定义的“属性”(表属性配置文件)定义了一个“值”(表属性值)。

可能最相关的部分在底部,其中“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
;

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

  • 产品
  • propertyprofile - 所有产品都具有的特征(例如高度、价格)
  • propertyvalue - 特定特征的数据;与财产概况有关(例如 5 厘米;120 美元)

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")
                        }
                    )
        })
4

1 回答 1

0

分析

问题似乎是休眠没有..

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

事实上,hibernate 似乎匹配两个实体,它们应该进入 List 的同一个条目,基于主键属性,即这样的:

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

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

解决方案

使用考虑“ProductDataFillSummary_ProductInformation.productId”和“.propertyProfileId”的复合键,或者..

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

concat(p.ID, '-', pp.ID) as 'uuid'
于 2017-01-02T12:00:07.940 回答