簡體   English   中英

JPQL TREAT AS / LEFT OUTER JOIN

[英]JPQL TREAT AS /LEFT OUTER JOIN

我正在嘗試JPA 2.1(eclipselink)中的“TREAT AS”功能,我遇到了JPA的錯誤:

異常描述:ReportQuery結果大小不匹配。 期待[263],但檢索[197]

這是我的JPQL查詢(我將一些部分更改為更明確):

String jpql = "select distinct s, accountAD "
            + "from SheetAccountUser s "
            + "left join fetch s.userTarget target "
            + "left join TREAT(target.accounts AS ADAccount) accountAD ";

ADAccount是AbstractAccount的子類(@Inheritance(strategy = InheritanceType.JOINED)。用戶有一個AbstractAccount列表。

我想用userTarget的AD帳戶選擇工作表。 如果沒有userTarget或userTarget沒有AD帳戶(左連接),我想要null。

問題來自對待操作員。 SQL生成的查詢在AbstractAccount表和ADAccount表之間具有左連接。 這導致每個帳戶類型的targetUser檢索一行。

這是生成的SQL查詢:

SELECT DISTINCT 
t0.Id, --etc
t6.Id, t6.name, --etc
t7.userId --etc
FROM sheet t0 
LEFT OUTER JOIN user t6 ON (t6.Id = t0.userTargetId),
account t7 LEFT OUTER JOIN ad_account t8 ON ((t8.userId = t7.userId) AND (t8.idApp = t7.idApp))
WHERE (t7.userId = t6.Id) AND (t7.DTYPE = 'ADAccount');

我們可以在帳戶和ad_account之間看到左外連接。 此外,select子句中不存在ad_account表。 (idApp字段是主鍵的一部分,並保持唯一(userId,idApp)約束)。 我不知道這是我的理解或JPA的問題。

感謝你們對我的幫助!

 "select distinct s, accountAD "
                + "from SheetAccountUser s "
                + "left join fetch s.userTarget target "
                + "left join target.accounts accountAD where TYPE(accountAD) = ADAccount";

此請求不會返回具有沒有AD帳戶的目標的工作表。

 "select distinct s, accountAD "
                + "from SheetAccountUser s "
                + "left join fetch s.userTarget target "
                + "left join target.accounts accounts "
                + " join TREAT(accounts AS ADAccount) accountAD";

這個生成與我的第一個jpql請求相同的SQL並生成Eclipselink錯誤。

如果目標有一個AD帳戶和至少一個其他帳戶類型,我還有一個工作表的多行:一行設置了AD帳戶屬性,另一行設置了空值(這些不同的值阻止了distinct子句,因此DTYPE值也是如此)。

幸運的是,我只需要2個關於AD帳戶的信息:它的存在和一個布爾“停用”。

經過更多的反思,我有了一個想法:

    "select u, "
                // 0 if line with no target or no ADAccount or with another account type, else 1 (one 1 by sheet/target) 
                + "sum( "
                + "     case "
                + "     when accountAD.desactivated is not null then 1 "
                + "     else 0 "
                + "     end "
                + ") as ADAccountExists, "
                // the target have an AD Account desactivated
                + "sum( " 
                + "     case "
                + "     when compteAD.desactivated = 1 then 1 " 
                + "     else 0 "
                + "     end" 
                + ") as ADAccountDesactivated " 
                + "from SheetAccountUser s "
                + "left join fetch s.userTarget target "
                + "left join treat(target.accounts as ADAccount) accountAD "
                + "group by s,target " //the group by maintains unicity of the sheets

它工作正常,但它非常難看。 我有一天會跳過另一種方法。

TREAT表達式意味着允許在查詢中訪問子類的參數; 過濾是必要的副產品,但不是主要意圖。 您可能希望查詢“工資> 100k的工人或管理人員數量<10”的人員。 在這種情況下,人員+員工與人員+經理之間的嚴格聯系會妨礙查詢。

TYPE表達式允許您自己控制過濾,以便獲得您正在尋找的嚴格結果。 就像是:

"select distinct s, accountAD "
            + "from SheetAccountUser s "
            + "left join fetch s.userTarget target "
            + "left join target.accounts accountAD where TYPE(accountAD) = ADAccount";

可能更多你需要的東西。 請記住,您需要明確列出您想要包含的任何子類。

如果必須使用Treat來過濾,但希望外部聯接超過target.accounts,請嘗試以下方法:

"select distinct s, accountAD "
                + "from SheetAccountUser s "
                + "left join fetch s.userTarget target "
                + "left join target.accounts accounts "
                + " join TREAT(accounts AS ADAccount) accountAD";

可能會工作,但您可能只想在需要時在where子句中使用TREAT。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM