【问题标题】:Different result for @SQLResultSetMapping+Joins on multiple entities | JPA@SQLResultSetMapping+Joins 在多个实体上的不同结果 | JPA
【发布时间】:2017-05-15 02:30:29
【问题描述】:

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

--- 概述---

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

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

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

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

问题

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

pp.id 列是一个连接列,我想我在 JPA 中对 Joins + SQLResultSetMappings 有误解。在我看来,不同之处在于 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")
                        }
                    )
        })

【问题讨论】:

    标签: mysql hibernate jpa nativequery sqlresultsetmapping


    【解决方案1】:

    分析

    问题似乎是 Hibernate 没有..

    • .. 处理每一行
    • .. 每行映射到指定实体
    • .. 将此行的映射实体放入 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'
    

    【讨论】:

      猜你喜欢
      • 2014-08-10
      • 2010-11-20
      • 2015-01-18
      • 1970-01-01
      • 2011-12-12
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      相关资源
      最近更新 更多