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);
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!