我正在尝试" TREAT AS"来自JPA 2.1(eclipselink)的功能,我遇到了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是否有问题。
谢谢你的帮助!
答案 0 :(得分:1)
"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
它工作正常,但非常难看。我有一天会跳过另一种方法。
答案 1 :(得分:0)
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。