隐式多对一路径JOIN
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
3.19 版本中添加了对 to-many
路径(隐式 或 显式)的支持。虽然显式 to-many
路径非常强大,但用户可能希望像隐式 to-one
路径一样方便地使用隐式 to-many
路径。然而,jOOQ 不像其他 ORM 那样开箱即用地支持这些路径,并且用户在简单示例中可能会期望支持。例如,考虑以下“显而易见”的示例
// Get all authors and count their books create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, count(AUTHOR.book().ID)) .from(AUTHOR) .groupBy(AUTHOR.ID) .fetch();
它读起来很流畅:“获取所有作者并计算他们的书籍数量”。预期生成的查询是
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, COUNT(BOOK.ID) FROM AUTHOR LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID GROUP BY AUTHOR.ID
另一个很酷的例子是这个巧妙的 ANTI JOIN
// Get all authors without any book create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(AUTHOR) .where(AUTHOR.book().ID.isNull()) .fetch();
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME FROM AUTHOR LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID WHERE BOOK.ID IS NULL
// Get all authors with books create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(AUTHOR) .where(AUTHOR.book().ID.isNotNull()) .fetch();
SELECT AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME FROM AUTHOR LEFT JOIN BOOK ON BOOK.AUTHOR_ID = AUTHOR.ID WHERE BOOK.ID IS NOT NULL
现在,我们得到了重复的作者。每个作者的书籍都有一份,这是由于 LEFT JOIN
创建的笛卡尔积。
偶然的重复对象并不是这种隐式to-many
路径 JOIN 会导致的主要问题。主要问题是,放置在 SELECT 子句 或 WHERE 子句(和其他子句)中的隐式to-many
路径将能够生成行,而实际上SELECT
仅转换行(如Stream.map()
),WHERE
仅过滤行(如Stream.filter()
)。这些子句能够有效地生成行将是非常不符合 SQL 习惯的,并且令人困惑。
为了防止这种情况,当遇到隐式 to-many
JOIN 路径表达式时,默认行为是抛出一个异常。
为了防止这种情况,用户有两种选择
- 使用 Settings.renderImplicitJoinToManyType 覆盖默认设置。这适用于所有查询,并为知道自己在做什么的高级用户删除了上述标量子查询保护。
- 使用 显式路径 JOIN 来指定确实需要
LEFT JOIN
(或任何其他类型的JOIN
),请参见以下示例
// Get all authors with books create.select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME) .from(AUTHOR) .leftJoin(AUTHOR.book()) // Now, the LEFT JOIN is explicit and cartesian products aren't accidental. .where(AUTHOR.book().ID.isNotNull()) .fetch();
反馈
您对此页面有任何反馈吗? 我们很乐意听到!