可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15

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);

反馈

您对此页面有任何反馈吗? 我们很乐意听取您的意见!

The jOOQ Logo