简体   繁体   English

JPQL TREAT AS / LEFT OUTER JOIN

[英]JPQL TREAT AS /LEFT OUTER JOIN

I'm trying the "TREAT AS" function from JPA 2.1 (eclipselink) and I'm stuck with an error from JPA: 我正在尝试JPA 2.1(eclipselink)中的“TREAT AS”功能,我遇到了JPA的错误:

Exception Description: ReportQuery result size mismatch. 异常描述:ReportQuery结果大小不匹配。 Expecting [263], but retrieved [197] 期待[263],但检索[197]

Here is my JPQL query (I change some parts to be more explicit): 这是我的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 is a subclass from AbstractAccount (@Inheritance(strategy = InheritanceType.JOINED). A User have a list of AbstractAccount. ADAccount是AbstractAccount的子类(@Inheritance(strategy = InheritanceType.JOINED)。用户有一个AbstractAccount列表。

I want to select sheets with the AD account of the userTarget. 我想用userTarget的AD帐户选择工作表。 I want null if there is no userTarget or if the userTarget has no AD account (left join). 如果没有userTarget或userTarget没有AD帐户(左连接),我想要null。

The problem comes from the treat operator. 问题来自对待操作员。 The SQL generated query have a left join between the AbstractAccount table and the ADAccount table. SQL生成的查询在AbstractAccount表和ADAccount表之间具有左连接。 This cause the retrieve of one line per account type of the targetUser. 这导致每个帐户类型的targetUser检索一行。

Here is the SQL query generated: 这是生成的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');

We can see the left outer join between account and ad_account. 我们可以在帐户和ad_account之间看到左外连接。 Also, the ad_account table is not present in the select clause. 此外,select子句中不存在ad_account表。 (The idApp field is a part of the primary key and maintain the unique (userId, idApp) constraint). (idApp字段是主键的一部分,并保持唯一(userId,idApp)约束)。 I don't know if it's a problem with my understanding or JPA. 我不知道这是我的理解或JPA的问题。

Thank you for helping me! 感谢你们对我的帮助!

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

This request doesn't return sheet that have a target without AD Account. 此请求不会返回具有没有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";

This one generate the same SQL that my first jpql request and generate an Eclipselink error. 这个生成与我的第一个jpql请求相同的SQL并生成Eclipselink错误。

I also have multiple lines for one sheet if the target has one AD Account and at least one other Account type: One line with the AD Account attributes setted and others with null values (these different values block the distinct clause, so do the DTYPE value). 如果目标有一个AD帐户和至少一个其他帐户类型,我还有一个工作表的多行:一行设置了AD帐户属性,另一行设置了空值(这些不同的值阻止了distinct子句,因此DTYPE值也是如此)。

Fortunately, I just need 2 informations about AD Account: Its existence and one boolean "desactivated". 幸运的是,我只需要2个关于AD帐户的信息:它的存在和一个布尔“停用”。

After more reflexion I had an idea: 经过更多的反思,我有了一个想法:

    "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

It's working fine but it's very ugly. 它工作正常,但它非常难看。 I hoppe someday to find another method. 我有一天会跳过另一种方法。

The TREAT expression is meant as a way of allowing access a subclass' parameters within the query; TREAT表达式意味着允许在查询中访问子类的参数; filtering is a necessary byproduct but not the main intent. 过滤是必要的副产品,但不是主要意图。 It is more along the lines where you might want a query for "People who are workers with a salary > 100k or people who are managers with the number of directs <10". 您可能希望查询“工资> 100k的工人或管理人员数量<10”的人员。 In that case, a strict join between the people+employees and people+managers would hinder the query. 在这种情况下,人员+员工与人员+经理之间的严格联系会妨碍查询。

The TYPE expression allows you to control the filtering yourself so that you get the strict results you are looking for. TYPE表达式允许您自己控制过滤,以便获得您正在寻找的严格结果。 Something like: 就像是:

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

Might be more what you need. 可能更多你需要的东西。 Remember that you will need to explicitly list any subclasses you want included though. 请记住,您需要明确列出您想要包含的任何子类。

If you must use Treat to filter but want outer joins over target.accounts, try something like: 如果必须使用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";

might work, though you may want to just use the TREAT within the where clause when needed. 可能会工作,但您可能只想在需要时在where子句中使用TREAT。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM