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 内存中的作者和书籍。
数据库架构包含 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 内存中的作者和书籍。