Вопрос N+1 о двунаправленной связи один на один с Jpa и Hibernate
Выполняемый запрос:
from PurchaseOrder o join fetch o.basket where o.statusE in (:statuses)
Сопоставление в PurchaseOrder:
@OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="basket_id")
public ShoppingBasket getBasket() {
return this.basket;
}
Отображение в ShoppingBasket:
@OneToOne(mappedBy = "basket", cascade=CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@Fetch(FetchMode.JOIN)
public PurchaseOrder getOrder() {
return order;
}
Когда этот запрос выполняется, он переводится в следующие запросы:
- 1 запрос следующего типа, извлекающий все корзины и заказы для данного статуса
select PurchaseOrder.*, ShoppingBasket.* /* changed for simplicity */
from purchaseorders purchaseor0_
inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id
where purchaseor0_.status in (? , ? , ?)
order by purchaseor0_.created DESC limit ?
- n запросов следующего типа, по одному для каждого результата корзины в предыдущем запросе, чтобы получить связанный заказ
select pPurchaseOrder.* /* changed for simplicity */
from purchaseorders purchaseor0_
where purchaseor0_.basket_id=?
Я попытался изменить стратегию выборки (я знаю, что она игнорируется при использовании HQL в любом случае), изменив план выборки и атрибут "опционально" из отчаяния. Есть ли способ заставить Hibernate загружать PurchaseOrders с соответствующими ShoppingBaskets в одном запросе? Должен ли я использовать инструментарий байт-кода для достижения этого, и если да, то как?
Журнал отладки Hibernate выглядит следующим образом:
DEBUG JDBCTransaction - begin
DEBUG ConnectionManager - opening JDBC connection
DEBUG JDBCTransaction - current autocommit status: true
DEBUG JDBCTransaction - disabling autocommit
DEBUG QueryTranslatorImpl - parse() - HQL: from com.ng.ticketlogic.core.shop.PurchaseOrder o join fetch o.basket where o.statusE in (:statuses) ORDER BY o.created DESC
DEBUG AST - --- HQL AST ---
\-[QUERY] Node: 'query'
+-[SELECT_FROM] Node: 'SELECT_FROM'
| \-[FROM] Node: 'from'
| +-[RANGE] Node: 'RANGE'
| | +-[DOT] Node: '.'
| | | +-[DOT] Node: '.'
| | | | +-[DOT] Node: '.'
| | | | | +-[DOT] Node: '.'
| | | | | | +-[DOT] Node: '.'
| | | | | | | +-[IDENT] Node: 'com'
| | | | | | | \-[IDENT] Node: 'ng'
| | | | | | \-[IDENT] Node: 'ticketlogic'
| | | | | \-[IDENT] Node: 'core'
| | | | \-[IDENT] Node: 'shop'
| | | \-[IDENT] Node: 'PurchaseOrder'
| | \-[ALIAS] Node: 'o'
| \-[JOIN] Node: 'join'
| +-[FETCH] Node: 'fetch'
| \-[DOT] Node: '.'
| +-[IDENT] Node: 'o'
| \-[IDENT] Node: 'basket'
+-[WHERE] Node: 'where'
| \-[IN] Node: 'in'
| +-[DOT] Node: '.'
| | +-[IDENT] Node: 'o'
| | \-[IDENT] Node: 'statusE'
| \-[IN_LIST] Node: 'inList'
| \-[COLON] Node: ':'
| \-[IDENT] Node: 'statuses'
\-[ORDER] Node: 'ORDER'
+-[DOT] Node: '.'
| +-[IDENT] Node: 'o'
| \-[IDENT] Node: 'created'
\-[DESCENDING] Node: 'DESC'
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG HqlSqlBaseWalker - select << begin [level=1, statement=select]
DEBUG FromElement - FromClause{level=1} : com.ng.ticketlogic.core.shop.PurchaseOrder (o) -> purchaseor0_
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : basket -> org.hibernate.type.ManyToOneType(com.ng.ticketlogic.core.shop.ShoppingBasket)
DEBUG DotNode - dereferenceEntityJoin() : generating join for basket in com.ng.ticketlogic.core.shop.PurchaseOrder {no alias} parent = [ {null} ]
DEBUG FromElement - FromClause{level=1} : com.ng.ticketlogic.core.shop.ShoppingBasket (no alias) -> shoppingba1_
DEBUG FromClause - addJoinByPathMap() : o.basket -> FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
DEBUG FromReferenceNode - Resolved : o.basket -> purchaseor0_.basket_id
DEBUG HqlSqlWalker - createFromJoinElement() : -- join tree --
\-[JOIN_FRAGMENT] FromElement: 'shoppingbaskets shoppingba1_' FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : statusE -> org.hibernate.type.CustomType@493744b6
DEBUG FromReferenceNode - Resolved : o.statusE -> purchaseor0_.status
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : created -> org.hibernate.type.TimestampType@69a4e343
DEBUG FromReferenceNode - Resolved : o.created -> purchaseor0_.created
DEBUG HqlSqlBaseWalker - select : finishing up [level=1, statement=select]
DEBUG HqlSqlWalker - processQuery() : ( SELECT ( FromClause{level=1} ( purchaseorders purchaseor0_ shoppingbaskets shoppingba1_ ) ) ( where ( in ( purchaseor0_.status purchaseor0_.id statusE ) ( inList ? ) ) ) ( ORDER ( purchaseor0_.created purchaseor0_.id created ) DESC ) )
DEBUG HqlSqlWalker - Derived SELECT clause created.
DEBUG JoinProcessor - Using FROM fragment [purchaseorders purchaseor0_]
DEBUG JoinProcessor - Using FROM fragment [inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id]
DEBUG HqlSqlBaseWalker - select >> end [level=1, statement=select]
DEBUG AST - --- SQL AST ---
\-[SELECT] QueryNode: 'SELECT' querySpaces (purchaseorders,shoppingbaskets)
+-[SELECT_CLAUSE] SelectClause: '{derived select clause}'
| +-[SELECT_EXPR] SelectExpressionImpl: 'purchaseor0_.id as id10_0_' {FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=o,role=null,tableName=purchaseorders,tableAlias=purchaseor0_,origin=null,columns={,className=com.ng.ticketlogic.core.shop.PurchaseOrder}}}
| +-[SELECT_EXPR] SelectExpressionImpl: 'shoppingba1_.id as id9_1_' {FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}}
| +-[SQL_TOKEN] SqlFragment: 'purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_'
| \-[SQL_TOKEN] SqlFragment: 'shoppingba1_.call_center as call2_9_1_, shoppingba1_.call_center_fee as call3_9_1_, shoppingba1_.cardCharge as cardCharge9_1_, shoppingba1_.created as created9_1_, shoppingba1_.currency as currency9_1_, shoppingba1_.deliveryCost as delivery6_9_1_, shoppingba1_.delivery_option as delivery14_9_1_, shoppingba1_.deliveryType as delivery7_9_1_, shoppingba1_.insurance as insurance9_1_, shoppingba1_.owner as owner9_1_, shoppingba1_.promotionCode_id as promoti15_9_1_, shoppingba1_.status as status9_1_, shoppingba1_.unique_id as unique11_9_1_, shoppingba1_.updated as updated9_1_'
+-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=2, fromElements=2, fromElementByClassAlias=[o], fromElementByTableAlias=[purchaseor0_, shoppingba1_], fromElementsByPath=[o.basket], collectionJoinFromElementsByPath=[], impliedElements=[]}
| \-[FROM_FRAGMENT] FromElement: 'purchaseorders purchaseor0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=o,role=null,tableName=purchaseorders,tableAlias=purchaseor0_,origin=null,columns={,className=com.ng.ticketlogic.core.shop.PurchaseOrder}}
| \-[JOIN_FRAGMENT] FromElement: 'inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id' FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
+-[WHERE] SqlNode: 'where'
| \-[IN] InLogicOperatorNode: 'in'
| +-[DOT] DotNode: 'purchaseor0_.status' {propertyName=statusE,dereferenceType=ALL,propertyPath=statusE,path=o.statusE,tableAlias=purchaseor0_,className=com.ng.ticketlogic.core.shop.PurchaseOrder,classAlias=o}
| | +-[ALIAS_REF] IdentNode: 'purchaseor0_.id' {alias=o, className=com.ng.ticketlogic.core.shop.PurchaseOrder, tableAlias=purchaseor0_}
| | \-[IDENT] IdentNode: 'statusE' {originalText=statusE}
| \-[IN_LIST] SqlNode: 'inList'
| \-[NAMED_PARAM] ParameterNode: '?' {name=statuses, expectedType=org.hibernate.type.CustomType@493744b6}
\-[ORDER] OrderByClause: 'ORDER'
+-[DOT] DotNode: 'purchaseor0_.created' {propertyName=created,dereferenceType=ALL,propertyPath=created,path=o.created,tableAlias=purchaseor0_,className=com.ng.ticketlogic.core.shop.PurchaseOrder,classAlias=o}
| +-[ALIAS_REF] IdentNode: 'purchaseor0_.id' {alias=o, className=com.ng.ticketlogic.core.shop.PurchaseOrder, tableAlias=purchaseor0_}
| \-[IDENT] IdentNode: 'created' {originalText=created}
\-[DESCENDING] SqlNode: 'DESC'
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG QueryTranslatorImpl - HQL: from com.ng.ticketlogic.core.shop.PurchaseOrder o join fetch o.basket where o.statusE in (:statuses) ORDER BY o.created DESC
DEBUG QueryTranslatorImpl - SQL: select purchaseor0_.id as id10_0_, shoppingba1_.id as id9_1_, purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_, shoppingba1_.call_center as call2_9_1_, shoppingba1_.call_center_fee as call3_9_1_, shoppingba1_.cardCharge as cardCharge9_1_, shoppingba1_.created as created9_1_, shoppingba1_.currency as currency9_1_, shoppingba1_.deliveryCost as delivery6_9_1_, shoppingba1_.delivery_option as delivery14_9_1_, shoppingba1_.deliveryType as delivery7_9_1_, shoppingba1_.insurance as insurance9_1_, shoppingba1_.owner as owner9_1_, shoppingba1_.promotionCode_id as promoti15_9_1_, shoppingba1_.status as status9_1_, shoppingba1_.unique_id as unique11_9_1_, shoppingba1_.updated as updated9_1_ from purchaseorders purchaseor0_ inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id where purchaseor0_.status in (?) order by purchaseor0_.created DESC
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG QueryTranslatorImpl - parse() - HQL: from com.ng.ticketlogic.core.shop.PurchaseOrder o join fetch o.basket where o.statusE in (:statuses0_, :statuses1_, :statuses2_) ORDER BY o.created DESC
DEBUG AST - --- HQL AST ---
\-[QUERY] Node: 'query'
+-[SELECT_FROM] Node: 'SELECT_FROM'
| \-[FROM] Node: 'from'
| +-[RANGE] Node: 'RANGE'
| | +-[DOT] Node: '.'
| | | +-[DOT] Node: '.'
| | | | +-[DOT] Node: '.'
| | | | | +-[DOT] Node: '.'
| | | | | | +-[DOT] Node: '.'
| | | | | | | +-[IDENT] Node: 'com'
| | | | | | | \-[IDENT] Node: 'ng'
| | | | | | \-[IDENT] Node: 'ticketlogic'
| | | | | \-[IDENT] Node: 'core'
| | | | \-[IDENT] Node: 'shop'
| | | \-[IDENT] Node: 'PurchaseOrder'
| | \-[ALIAS] Node: 'o'
| \-[JOIN] Node: 'join'
| +-[FETCH] Node: 'fetch'
| \-[DOT] Node: '.'
| +-[IDENT] Node: 'o'
| \-[IDENT] Node: 'basket'
+-[WHERE] Node: 'where'
| \-[IN] Node: 'in'
| +-[DOT] Node: '.'
| | +-[IDENT] Node: 'o'
| | \-[IDENT] Node: 'statusE'
| \-[IN_LIST] Node: 'inList'
| +-[COLON] Node: ':'
| | \-[IDENT] Node: 'statuses0_'
| +-[COLON] Node: ':'
| | \-[IDENT] Node: 'statuses1_'
| \-[COLON] Node: ':'
| \-[IDENT] Node: 'statuses2_'
\-[ORDER] Node: 'ORDER'
+-[DOT] Node: '.'
| +-[IDENT] Node: 'o'
| \-[IDENT] Node: 'created'
\-[DESCENDING] Node: 'DESC'
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG HqlSqlBaseWalker - select << begin [level=1, statement=select]
DEBUG FromElement - FromClause{level=1} : com.ng.ticketlogic.core.shop.PurchaseOrder (o) -> purchaseor0_
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : basket -> org.hibernate.type.ManyToOneType(com.ng.ticketlogic.core.shop.ShoppingBasket)
DEBUG DotNode - dereferenceEntityJoin() : generating join for basket in com.ng.ticketlogic.core.shop.PurchaseOrder {no alias} parent = [ {null} ]
DEBUG FromElement - FromClause{level=1} : com.ng.ticketlogic.core.shop.ShoppingBasket (no alias) -> shoppingba1_
DEBUG FromClause - addJoinByPathMap() : o.basket -> FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
DEBUG FromReferenceNode - Resolved : o.basket -> purchaseor0_.basket_id
DEBUG HqlSqlWalker - createFromJoinElement() : -- join tree --
\-[JOIN_FRAGMENT] FromElement: 'shoppingbaskets shoppingba1_' FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : statusE -> org.hibernate.type.CustomType@493744b6
DEBUG FromReferenceNode - Resolved : o.statusE -> purchaseor0_.status
DEBUG FromReferenceNode - Resolved : o -> purchaseor0_.id
DEBUG DotNode - getDataType() : created -> org.hibernate.type.TimestampType@69a4e343
DEBUG FromReferenceNode - Resolved : o.created -> purchaseor0_.created
DEBUG HqlSqlBaseWalker - select : finishing up [level=1, statement=select]
DEBUG HqlSqlWalker - processQuery() : ( SELECT ( FromClause{level=1} ( purchaseorders purchaseor0_ shoppingbaskets shoppingba1_ ) ) ( where ( in ( purchaseor0_.status purchaseor0_.id statusE ) ( inList ? ? ? ) ) ) ( ORDER ( purchaseor0_.created purchaseor0_.id created ) DESC ) )
DEBUG HqlSqlWalker - Derived SELECT clause created.
DEBUG JoinProcessor - Using FROM fragment [purchaseorders purchaseor0_]
DEBUG JoinProcessor - Using FROM fragment [inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id]
DEBUG HqlSqlBaseWalker - select >> end [level=1, statement=select]
DEBUG AST - --- SQL AST ---
\-[SELECT] QueryNode: 'SELECT' querySpaces (purchaseorders,shoppingbaskets)
+-[SELECT_CLAUSE] SelectClause: '{derived select clause}'
| +-[SELECT_EXPR] SelectExpressionImpl: 'purchaseor0_.id as id10_0_' {FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=o,role=null,tableName=purchaseorders,tableAlias=purchaseor0_,origin=null,columns={,className=com.ng.ticketlogic.core.shop.PurchaseOrder}}}
| +-[SELECT_EXPR] SelectExpressionImpl: 'shoppingba1_.id as id9_1_' {FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}}
| +-[SQL_TOKEN] SqlFragment: 'purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_'
| \-[SQL_TOKEN] SqlFragment: 'shoppingba1_.call_center as call2_9_1_, shoppingba1_.call_center_fee as call3_9_1_, shoppingba1_.cardCharge as cardCharge9_1_, shoppingba1_.created as created9_1_, shoppingba1_.currency as currency9_1_, shoppingba1_.deliveryCost as delivery6_9_1_, shoppingba1_.delivery_option as delivery14_9_1_, shoppingba1_.deliveryType as delivery7_9_1_, shoppingba1_.insurance as insurance9_1_, shoppingba1_.owner as owner9_1_, shoppingba1_.promotionCode_id as promoti15_9_1_, shoppingba1_.status as status9_1_, shoppingba1_.unique_id as unique11_9_1_, shoppingba1_.updated as updated9_1_'
+-[FROM] FromClause: 'from' FromClause{level=1, fromElementCounter=2, fromElements=2, fromElementByClassAlias=[o], fromElementByTableAlias=[purchaseor0_, shoppingba1_], fromElementsByPath=[o.basket], collectionJoinFromElementsByPath=[], impliedElements=[]}
| \-[FROM_FRAGMENT] FromElement: 'purchaseorders purchaseor0_' FromElement{explicit,not a collection join,not a fetch join,fetch non-lazy properties,classAlias=o,role=null,tableName=purchaseorders,tableAlias=purchaseor0_,origin=null,columns={,className=com.ng.ticketlogic.core.shop.PurchaseOrder}}
| \-[JOIN_FRAGMENT] FromElement: 'inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id' FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=null,role=null,tableName=shoppingbaskets,tableAlias=shoppingba1_,origin=purchaseorders purchaseor0_,columns={purchaseor0_.basket_id ,className=com.ng.ticketlogic.core.shop.ShoppingBasket}}
+-[WHERE] SqlNode: 'where'
| \-[IN] InLogicOperatorNode: 'in'
| +-[DOT] DotNode: 'purchaseor0_.status' {propertyName=statusE,dereferenceType=ALL,propertyPath=statusE,path=o.statusE,tableAlias=purchaseor0_,className=com.ng.ticketlogic.core.shop.PurchaseOrder,classAlias=o}
| | +-[ALIAS_REF] IdentNode: 'purchaseor0_.id' {alias=o, className=com.ng.ticketlogic.core.shop.PurchaseOrder, tableAlias=purchaseor0_}
| | \-[IDENT] IdentNode: 'statusE' {originalText=statusE}
| \-[IN_LIST] SqlNode: 'inList'
| +-[NAMED_PARAM] ParameterNode: '?' {name=statuses0_, expectedType=org.hibernate.type.CustomType@493744b6}
| +-[NAMED_PARAM] ParameterNode: '?' {name=statuses1_, expectedType=org.hibernate.type.CustomType@493744b6}
| \-[NAMED_PARAM] ParameterNode: '?' {name=statuses2_, expectedType=org.hibernate.type.CustomType@493744b6}
\-[ORDER] OrderByClause: 'ORDER'
+-[DOT] DotNode: 'purchaseor0_.created' {propertyName=created,dereferenceType=ALL,propertyPath=created,path=o.created,tableAlias=purchaseor0_,className=com.ng.ticketlogic.core.shop.PurchaseOrder,classAlias=o}
| +-[ALIAS_REF] IdentNode: 'purchaseor0_.id' {alias=o, className=com.ng.ticketlogic.core.shop.PurchaseOrder, tableAlias=purchaseor0_}
| \-[IDENT] IdentNode: 'created' {originalText=created}
\-[DESCENDING] SqlNode: 'DESC'
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG QueryTranslatorImpl - HQL: from com.ng.ticketlogic.core.shop.PurchaseOrder o join fetch o.basket where o.statusE in (:statuses0_, :statuses1_, :statuses2_) ORDER BY o.created DESC
DEBUG QueryTranslatorImpl - SQL: select purchaseor0_.id as id10_0_, shoppingba1_.id as id9_1_, purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_, shoppingba1_.call_center as call2_9_1_, shoppingba1_.call_center_fee as call3_9_1_, shoppingba1_.cardCharge as cardCharge9_1_, shoppingba1_.created as created9_1_, shoppingba1_.currency as currency9_1_, shoppingba1_.deliveryCost as delivery6_9_1_, shoppingba1_.delivery_option as delivery14_9_1_, shoppingba1_.deliveryType as delivery7_9_1_, shoppingba1_.insurance as insurance9_1_, shoppingba1_.owner as owner9_1_, shoppingba1_.promotionCode_id as promoti15_9_1_, shoppingba1_.status as status9_1_, shoppingba1_.unique_id as unique11_9_1_, shoppingba1_.updated as updated9_1_ from purchaseorders purchaseor0_ inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id where purchaseor0_.status in (? , ? , ?) order by purchaseor0_.created DESC
DEBUG ErrorCounter - throwQueryException() : no errors
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - select purchaseor0_.id as id10_0_, shoppingba1_.id as id9_1_, purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_, shoppingba1_.call_center as call2_9_1_, shoppingba1_.call_center_fee as call3_9_1_, shoppingba1_.cardCharge as cardCharge9_1_, shoppingba1_.created as created9_1_, shoppingba1_.currency as currency9_1_, shoppingba1_.deliveryCost as delivery6_9_1_, shoppingba1_.delivery_option as delivery14_9_1_, shoppingba1_.deliveryType as delivery7_9_1_, shoppingba1_.insurance as insurance9_1_, shoppingba1_.owner as owner9_1_, shoppingba1_.promotionCode_id as promoti15_9_1_, shoppingba1_.status as status9_1_, shoppingba1_.unique_id as unique11_9_1_, shoppingba1_.updated as updated9_1_ from purchaseorders purchaseor0_ inner join shoppingbaskets shoppingba1_ on purchaseor0_.basket_id=shoppingba1_.id where purchaseor0_.status in (? , ? , ?) order by purchaseor0_.created DESC limit ?
DEBUG AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#615430], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1608284]
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#614920], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1607774]
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#614875], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1607729]
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#610567], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1603430]
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#608160], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1601039]
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#601660], EntityKey[com.ng.ticketlogic.core.shop.ShoppingBasket#1594566]
DEBUG AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG TwoPhaseLoad - resolving associations for [com.ng.ticketlogic.core.shop.PurchaseOrder#615430]
DEBUG TwoPhaseLoad - done materializing entity [com.ng.ticketlogic.core.shop.PurchaseOrder#615430]
DEBUG TwoPhaseLoad - resolving associations for [com.ng.ticketlogic.core.shop.ShoppingBasket#1608284]
DEBUG Loader - loading entity: [com.ng.ticketlogic.core.shop.PurchaseOrder#1608284]
DEBUG AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG SQL - select purchaseor0_.id as id10_0_, purchaseor0_.address_id as address17_10_0_, purchaseor0_.affiliate_id as affiliate18_10_0_, purchaseor0_.agreed_cardholder as agreed2_10_0_, purchaseor0_.agreed_terms as agreed3_10_0_, purchaseor0_.alternativeCustomerName as alternat4_10_0_, purchaseor0_.approved as approved10_0_, purchaseor0_.author as author10_0_, purchaseor0_.basket_id as basket19_10_0_, purchaseor0_.card_id as card20_10_0_, purchaseor0_.created as created10_0_, purchaseor0_.editor as editor10_0_, purchaseor0_.groupBookingId as groupBo21_10_0_, purchaseor0_.ip_address as ip9_10_0_, purchaseor0_.linkedOrder as linkedO22_10_0_, purchaseor0_.manual_hold as manual10_10_0_, purchaseor0_.manual_review as manual11_10_0_, purchaseor0_.partner_id as partner23_10_0_, purchaseor0_.platformType as platfor12_10_0_, purchaseor0_.reference as reference10_0_, purchaseor0_.status as status10_0_, purchaseor0_.updated as updated10_0_, purchaseor0_.user_id as user24_10_0_, purchaseor0_.views as views10_0_ from purchaseorders purchaseor0_ where purchaseor0_.basket_id=?
DEBUG AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
DEBUG Loader - result row: EntityKey[com.ng.ticketlogic.core.shop.PurchaseOrder#615430]
DEBUG AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
DEBUG AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG Loader - done entity load
DEBUG TwoPhaseLoad - done materializing entity [com.ng.ticketlogic.core.shop.ShoppingBasket#1608284]
1 ответ
С помощью FetchMode.JOIN
отключает ленивую загрузку. В результате поведение может быть не тем, что вы ожидаете. Попробуй это:
@OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="basket_id")
public ShoppingBasket getBasket() {
return this.basket;
}
@OneToOne(mappedBy = "basket", cascade=CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
public PurchaseOrder getOrder() {
return order;
}
После этого ваш запрос приведет к выполнению только одного запроса к БД. Результат будет содержать список объектов PurchaseOrder, каждый из которых имеет правильно инициализированный атрибут корзины.
В качестве примечания: действительно ли необходимы двусторонние взаимовыгодные отношения один-к-одному? С точки зрения бизнеса, заказ на покупку создается после жизненного цикла корзины покупок, поэтому на него нет ссылки на него (он должен содержать список позиций заказа, созданных на основе содержимого корзины). Но это всего лишь предложение.