Ad-hoc 转换器
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
有时,您可能希望将一个临时的转换器附加到某个列,仅用于单个查询或一些本地查询。这可以通过多种方式实现。最方便的方法是调用 Field.convert() 和相关方法。假设您有一个转换器,可以将 SQL VARCHAR 列转换为 Language
enum Language { de, en, fr, it, pt; }
Converter<String, Language> converter = new EnumConverter<>(String.class, Language.class);
现在,您可以保持生成的代码为 Field<String>,而不是将它们附加到生成的代码,并在运行时将其转换为 Field<Language>,以用于单个查询的目的
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convert(converter))
.from(LANGUAGE)
.fetch();
或者,如果您甚至没有准备好 Converter 实例,您可以像这样将转换逻辑附加到字段
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convert(Language.class, Language::valueOf, Language::name))
.from(LANGUAGE)
.fetch();
或者,由于在这种情况下,转换仅从数据库类型(T 类型)发生到用户类型(U 类型),因此您可以使用 Field.convertFrom() 省略逆转换函数(“from”表示“从数据库读取”)
Result<Record2<Integer, Language>> result =
create.select(LANGUAGE.ID, LANGUAGE.CD.convertFrom(Language.class, Language::valueOf))
.from(LANGUAGE)
.fetch();
反之也是可能的,例如,当您只需要使用 Field.convertTo() 将用户类型(U 类型)转换为数据库类型(T 类型)时(“to”表示“写入数据库”)
Result<Record2<Integer, Language>> result =
create.insertInto(LANGUAGE)
.columns(LANGUAGE.ID, LANGUAGE.CD.convertTo(Language.class, Language::name))
.values(5, Language.it)
.execute();
在嵌套集合上使用 ad hoc 转换器
当在嵌套集合上使用 ad-hoc 转换器时,它们非常强大,例如使用 MULTISET 值构造函数 构造的那些
// Structurally typed result
Result<Record4<
String, // AUTHOR.FIRST_NAME
String, // AUTHOR.LAST_NAME
Result<Record2<
String, // LANGUAGE.CD
String // LANGUAGE.DESCRIPTION
>>, // books
Result<Record1<
String // BOOK_TO_BOOK_STORE.BOOK_STORE_NAME
>> // book_stores
>> result = create.select(
AUTHOR.FIRST_NAME,
AUTHOR.LAST_NAME,
multiset(
selectDistinct(
BOOK.language().CD,
BOOK.language().DESCRIPTION)
.from(BOOK)
.where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
).as("books"),
multiset(
selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
.from(BOOK_TO_BOOK_STORE)
.where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID
.eq(AUTHOR.ID))
).as("book_stores"))
.from(AUTHOR)
.orderBy(AUTHOR.ID)
.fetch();
有关 MULTISET 的详细信息,请参阅关于MULTISET 值构造函数的部分。现在,代替上述结构化类型的结果,可能希望将内容映射到 Java 16 record 类型或其他形式的 DTO
record Book(String cd, String description) {}
record BookStore(String name) {}
record Author(String firstName, String lastName, List<Book> books, List<BookStore> bookStores) {}
现在,使用静态导入友好的 org.jooq.Records 实用程序
// Nominally typed result, all type checked!
List<Author> result = create.select(
AUTHOR.FIRST_NAME,
AUTHOR.LAST_NAME,
// This is now a Field<List<Book>>
multiset(
selectDistinct(
BOOK.language().CD,
BOOK.language().DESCRIPTION)
.from(BOOK)
.where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
).as("books").convertFrom(r -> r.map(Records.mapping(Book::new))),
// This is now a Field<List<BookStore>>
multiset(
selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
.from(BOOK_TO_BOOK_STORE)
.where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
).as("book_stores").convertFrom(r -> r.map(Records.mapping(BookStore::new))))
.from(AUTHOR)
.orderBy(AUTHOR.ID)
.fetch(Records.mapping(Author::new));
尝试从投影中添加或删除列,或者从记录中添加或删除属性,查询将不再进行类型检查!
当然,通常的反射 RecordMapper API 仍然可以与这些 ad-hoc 转换器一起使用。
// Nominally typed result, but not strongly type checked
List<Author> result = create.select(
AUTHOR.FIRST_NAME,
AUTHOR.LAST_NAME,
// This is now a Field<List<Book>>
multiset(
selectDistinct(
BOOK.language().CD,
BOOK.language().DESCRIPTION)
.from(BOOK)
.where(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
).as("books").convertFrom(r -> r.into(Book.class)),
// This is now a Field<List<BookStore>>
multiset(
selectDistinct(BOOK_TO_BOOK_STORE.BOOK_STORE_NAME)
.from(BOOK_TO_BOOK_STORE)
.where(BOOK_TO_BOOK_STORE.tBook().AUTHOR_ID.eq(AUTHOR.ID))
).as("book_stores").convertFrom(r -> r.into(BookStore.class)))
.from(AUTHOR)
.orderBy(AUTHOR.ID)
.fetchInto(Author.class);
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!