类型安全映射一对一和一对多关系到记录

Type safe mapping one-to-one and one-to-many relationships to records

我想将一对一和一对多关系映射到生成的记录,最好以类型安全的方式。

我现在可以使用 Java 记录,但我宁愿使用代码生成的记录,这样我以后可以更轻松地更新它们,尽管我不需要记录的所有列。

我还有一个问题,不是没有将联系人映射到列表,而是映射到列表,而它确实正确映射了地址。

record BulkContactEdit(long id, String organizationName, List < Contact > contacts, Address visitedAddress) {}

record Contact(long id) {}

record Address(long id, String address, String state, String city, String zipcode, Long country_id) {}

var bce = BULK_CONTACT_EDIT.as("bce");
var bceContacts = BULK_CONTACT_EDIT_CONTACTS.as("bceContacts");
var rel = RELATION.as("rel");

var bceAddress = ADDRESS.as("bceAddress");

var query = jooq().select(
bce.ID, bce.ORGANIZATION_NAME,
// For some reason this doesn't map.
//                DSL.multisetAgg(rel.ID)
//                    .as("contacts")
//                    .convertFrom(r -> r.map(mapping(Contact::new))),
jsonArrayAgg(jsonObject(rel.ID)).as("contacts"), jsonObject(bceAddress.fields()).as("visitedAddress"))
// Same as above, but with redundant sub-query.
//                DSL.field(
//                        jooq()
//                            .select(jsonArrayAgg(jsonObject(rel.ID)))
//                            .from(rel)
//                            .where(rel.ID.eq(bceContacts.CONTACT_ID)))
//                    .as("contacts"))
.from(
bce.join(bceContacts).on(bceContacts.BULK_CONTACT_EDIT_ID.eq(bce.ID)).join(rel).on(rel.ID.eq(bceContacts.CONTACT_ID)).leftJoin(bceAddress).on(bceAddress.ID.eq(bce.VISIT_ADDRESS_ID)).where(bce.ID.eq(bulkContactEditId)));

var bulkContactEdit = query.fetchOneInto(BulkContactEdit.class);

关于类型安全

I want to map one-to-one and one-to-many relationships to generated Records, preferably in a type-safe manner.

如果你想要类型安全,你不应该使用你使用过的两个功能:

  • 手动 SQL/JSON API 用法,生成缺乏类型安全性的通用 JSON 文档
  • 通过 into(X.class) 调用的反射映射,它利用了 DefaultRecordMapper 的反射映射功能。

上面的做法没有错。 jOOQ 3.14 引入了 SQL/JSON 支持以及 mapping JSON documents to Java objects using Gson or Jackson 的功能,如果在类路径中找到的话。该方法只是类型不安全。

现在,让我们分别看一下您的各个问题,您似乎在混淆问题...

One-to-one映射

从 jOOQ 3.17(尚未发布,但很快)开始,the Table<R> type extends SelectField<R> for convenience,这意味着您可以将任何 table 表达式投影为嵌套记录,并将其映射到您自己的自定义记录(或不):

// Using implicit joins, mixing scalar values and nested records
Result<Record3<Long, String, AddressRecord>> r1 =
ctx.select(bce.ID, bce.ORGANIZATION_NAME, bce.address())
   .from(bce)
   .fetch();

// Using implicit joins, projecting only nested records
Result<Record2<BulkContactEditRecord, AddressRecord>> r1 =
ctx.select(bce, bce.address())
   .from(bce)
   .fetch();

虽然没有必要,但上面的示例使用了 implicit joins,这大大简化了这样的查询。当然,您可以像以前一样继续使用显式连接。

在 jOOQ 3.16 中,您可以通过 nested row() expression 的显式投影来做到这一点,就像这样。将嵌套记录映射到类型化的、生成的 UpdatableRecord 时没有类型安全,但我认为这是 acceptable,因为你仍在使用生成的代码,因此实际上不能有任何映射错误:

// Using implicit joins, mixing scalar values and nested records
Result<Record3<Long, String, AddressRecord>> r1 =
ctx.select(
        bce.ID, 
        bce.ORGANIZATION_NAME, 
        row(bce.address().fields()).convertFrom(r -> r.into(ADDRESS)))
   .from(bce)
   .fetch();

// Using implicit joins, projecting only nested records
Result<Record2<BulkContactEditRecord, AddressRecord>> r1 =
ctx.select(
        row(bce.fields()).convertFrom(r -> r.into(BULK_CONTACT_EDIT)), 
        row(bce.address().fields()).convertFrom(r -> r.into(ADDRESS)))
   .from(bce)
   .fetch();

One-to-many映射

当您使用 multisetAgg(rel.ID) 方法时,您的代码似乎出了问题,但我无法从您的问题中看出问题所在。另外,.

你的两个问题之间的唯一区别是,在这里,你不想使用 Java 记录,而是使用 jOOQ 生成的记录,在这种情况下你将使用这个习惯用法:

Field<Result<RelationRecord>> f = multisetAgg(rel.ID).convertFrom(r -> r.map(RELATION));