JOOQ,当右 table 对象不存在时如何处理左外连接结果

JOOQ, how to deal with left outer join results when right table object is not present

数据库架构包含 tables AUTHOR 和 BOOK,列如下:

AUTHOR: author_id, name
BOOK: book_id, name, author_id

我使用 JOOQ 将数据提取到 java。

我使用 POJO 书籍和作者:

public class Author { int author_id; String name; }
public class Book { int book_id; String name; }

和代码:

Result<Record> records = ctx.select()
            .from(AUTHOR)
            .leftOuterJoin(BOOK)
            .on(AUTHOR.AUTHOR_ID.eq(BOOK.AUTHOR_ID))
            .fetch();
Author author = records.get(0).into(Author.class);
Book book = records.get(0).into(Book.class);

问题是当没有作者的书时,book对象会填充默认值。如何检测左联接结果没有右联接的对象table?一种方法是检查书籍主键字段是否为空。还有其他办法吗?

对象模型想要表达的内容与 SQL 能够生成的内容之间存在概念上的不匹配。在对象模型中,人们喜欢将关系建模为嵌套集合,例如:

Author {
    List<Book> books;
}

而在 RDBMS 中,人们以相反的方式建模关系,在子实体上具有外键:

CREATE TABLE book (
    author_id bigint REFERENCES author(id)
)

从 SQL 生成嵌套集合(如在对象模型中)的最直接方法是使用 MULTISET 运算符,如 SQL 标准中指定:

SELECT
  author.*,
  MULTISET(
    SELECT * FROM book WHERE book.author_id = author.id
  ) AS books
FROM author;

遗憾的是,只有少数数据库支持此运算符,包括 Cubrid、Informix、Oracle 和 it can be emulated in PostgreSQL. Note that future versions of jOOQ will also support, and possibly emulate it

由于缺乏对此功能的支持,人们常常求助于一些技巧,例如:

  • 延迟加载
  • 运行 每个实体一个新查询
  • 运行 使用 LEFT JOIN 的单个查询,您的方式

所有这些方法都是 Hibernate 等 ORM 使用的技巧,each with their individual drawback, which is documented in this blog post。 ORM 并不总是"right" 选择技巧(或者更确切地说:用户没有正确配置 ORM),这就是为什么他们 运行 很多查询导致性能问题。

上述方法中最好的方法之一可能是 "new query per entity" 方法,您首先获取所有作者,然后在 2 个查询中获取每个作者的所有书籍 (not in N+1 queries!):

SELECT * FROM author WHERE [ some predicate ]
SELECT * FROM book WHERE author_id IN (SELECT id FROM author WHERE [ some predicate ])

然后您可以使用 jOOQ 实现每个结果,并使用散列图匹配 Java 内存中的作者和书籍。