我想将一对一和一对多的关系映射到生成的记录,最好是以类型安全的方式。
我现在可以使用Java记录,但我更愿意使用代码生成的records,这样之后我可以更容易地更新它们,尽管我不需要Record的所有列。
我还有一个问题,不是没有将联系人映射到列表,而是映射到列表中,而它确实正确地映射了地址。
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);
关于类型安全
我想将一对一和一对多的关系映射到生成的记录,最好是以类型安全的方式。
如果你想要类型安全,你不应该使用你使用过的两个功能:
- 手动使用SQL/JSON API,生成缺乏类型安全性的通用JSON文档
- 通过
into(X.class)
调用进行反射映射,该调用利用了DefaultRecordMapper
的反射映射功能
上述方法没有错。jOOQ 3.14引入了SQL/JSON支持,以及使用Gson或Jackson将JSON文档映射到Java对象的功能(如果在类路径中找到的话(。这种方法就是不安全。
现在,让我们单独来看一下你的个人问题,你似乎在混合担忧。。。
一对一映射
从jOOQ 3.17(尚未发布,但很快就会发布(开始,为了方便起见,Table<R>
类型扩展了SelectField<R>
,这意味着您可以将任何表表达式投影为嵌套记录,并将其映射到您自己的自定义记录(或不映射(:
// 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();
虽然没有必要,但上面的示例使用了隐式联接,这大大简化了这样的查询。当然,您可以像以前一样继续使用显式联接。
在jOOQ 3.16中,您可以通过嵌套row()
表达式的显式投影来实现这一点,如下所示。将嵌套记录映射到类型化、生成的UpdatableRecord
时没有类型安全性,但我认为这是可以接受的,因为您仍在使用生成的代码,因此不会出现任何映射错误:
// 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();
一对多映射
当您使用multisetAgg(rel.ID)
方法时,您的代码中似乎出现了问题,但我从您的问题中看不出问题出在哪里。此外,这与你之前的问题没有什么不同,之前的问题已经有了如何做到这一点的答案。
您的两个问题之间的唯一区别是,在这里,您不喜欢使用Java记录,而是使用jOOQ生成的记录,在这种情况下,您将使用以下习语:
Field<Result<RelationRecord>> f = multisetAgg(rel.ID).convertFrom(r -> r.map(RELATION));