5

I have a following query where I join tables A,B, and C:

  • C is related to B via C.B_ID
  • B is related to A via B.A_ID

I want to retrieve a report, where for each C, I want to retrieve also fields from corresponding B and A. If only a subset of fields is required, a projection and fetching to a POJO (with required properties from C, B, A) is an obvious approach.

class CReportDTO {
    Long c_id;
    Long c_field1;
    Long c_bid;
    Long b_field1;
    // ...
    CReportDTO(Long c_id, Long c_field1, Long c_bid, Long b_field1) {
        // ...
    }

    // ..
}
public List<CReportDTO> getPendingScheduledDeployments() {
        return dslContext.select(
                C.ID,
                C.FIELD1,
                C.B_ID,
                B.FIELD1,
                B.A_ID
                A.FIELD1,
                A.FIELD2
                )
                .from(C)
                .join(B)
                .on(C.B_ID.eq(B.ID))
                .join(A)
                .on(B.A_ID.eq(A.ID))
                .fetchInto(CReportDTO.class);
    };
}

My question

In case where all fields are needed I would prefer to have my report DTO contain A, B, C POJOs, without flattening them out:

class CReportDTO2 {
    C c;
    B b;
    A a;

    CReportDTO2(C c, B b, A a) {
        // ...
    }

    // ..
}

Is it possible to modify my query to:

  • include all fields from each table
  • massage it into CReportDTO2 without too much verbosity
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
Lesiak
  • 22,088
  • 2
  • 41
  • 65

1 Answers1

3

You can use a lesser known feature of jOOQ's DefaultRecordMapper by aliasing your fields using a dot notation that denotes the nesting structure of your DTO:

public List<CReportDTO> getPendingScheduledDeployments() {
    return dslContext.select(
    // Add these       vvvvvvvvvvvvvvvvvvvv
        C.ID       .as("c.c_id"),
        C.FIELD1   .as("c.c_field1"),
        C.B_ID     .as("c.b_id"),
        B.FIELD1   .as("b.b_field1"),
        B.A_ID     .as("b.a_id")
        A.FIELD1   .as("a.a_field1"),
        A.FIELD2   .as("a.a_field2")
    )
    .from(C)
    .join(B)
    .on(C.B_ID.eq(B.ID))
    .join(A)
    .on(B.A_ID.eq(A.ID))
    .fetchInto(CReportDTO2.class);
}

See Javadoc

If Field.getName() is MY_field.MY_nested_field (case-sensitive!), then this field's value will be considered a nested value MY_nested_field, which is set on a nested POJO

Note that this doesn't work with the constructor you've provided. You'll have to provide a default constructor as well, and make your fields non-final (in case they are).

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • I may be wrong, but the question seemed to be about fetching the related objects into the CReportDTO2. It also seems that you provided the answer to that on: https://stackoverflow.com/questions/38222957/jooq-can-i-fetch-a-join-of-two-tables-into-the-respective-pojos – Jason Warner Mar 11 '20 at 14:32
  • Thanks @LukasEder, I wasn't aware of that option. I was trying `var selectStep = dslContext.select(DSL.asterisk()).from....` and then `var a = selectStep.fetchInto(A.class)` etc, but this fails with `org.jooq.exception.MappingException` – Lesiak Mar 11 '20 at 14:42
  • @JasonWarner: That's just a typo. The linked question isn't strictly related. – Lukas Eder Mar 11 '20 at 15:03