FetchGroup

As an alternative to select and fetch we can use FetchGroup to specify what part of the object graph to fetch.

We can use FetchGroup with both query beans and standard queries.

FetchGroups provide a clean way to separate the definition of "what part of the object graph to load" (query tuning) from the definition of the query predicates (query business logic).

A FetchGroup is immutable, most often declared as a static final and can be combined to make other FetchGroups.

e.g. Just top level select properties

// immutable and threadsafe

static final QCustomer CUST = QCustomer.alias();

static final FetchGroup<Customer> fetch = QCustomer.forFetchGroup()
    .select(CUST.name, CUST.version, CUST.whenCreated)
    .buildFetchGroup();

...

List<Customer> customers =
  new QCustomer()
    .select(fetch)
    .name.istartsWith("Rob")
    .findList();

The above FetchGroup can be created without using query beans like the below:

static final FetchGroup<Customer> fetch =
    FetchGroup.of(Customer.class, "name, version, whenCreated"); // root level properties

 

e.g. select and fetch properties

// immutable and threadsafe

static final QCustomer CUST = QCustomer.alias();
static final QContact  CONT = QContact.alias();

static final FetchGroup<Customer> fetch = QCustomer.forFetchGroup()
    .select(CUST.name, CUST.version, CUST,whenCreated)
    .contacts.fetch(CONT.email)          // fetch the contacts with just their email
    .billingAddress.fetch()              // fetch all properties of billingAddress
    .buildFetchGroup();

...

List<Customer> customers =
  new QCustomer()
    .select(fetch)
    .name.istartsWith("Rob")
    .findList();

The above FetchGroup can be created without query beans by:

// immutable and threadsafe
static final FetchGroup<Customer> fetch =
   FetchGroup.of(Customer.class)
    .select("name, status")       // root level properties
    .fetch("contacts", "email")   // associated bean properties
    .build();

Example

This is a bigger example fetching orders with related lines, shipments, customer, customer.billingAddress and customer.contacts.

Note we control which properties (or all) are fetched on each path.

In this example we have several ToMany paths and we are using fetchQuery to explicitly control how the ORM query is broken into multiple SQL queries to build the graph.

// immutable and threadsafe

static final QOrder ORD = QOrder.alias();
static final QCustomer CUST = QCustomer.alias();
static final QContact CONT = QContact.alias();

static final FetchGroup<Order> fetch = QOrder.forFetchGroup()
    .customer.fetch(CUST.name, CUST.version, CUST,whenCreated)
    .customer.shippingAddress.fetch()
    .customer.contacts.fetch(CONT.email)                        // a ToMany path
    .lines.fetchQuery()                                         // a ToMany path
    .shipments.fetchQuery()                                     // a ToMany path
    .buildFetchGroup();

...

List<Order> orders =
  new QOrder()
    .select(fetch)
    .status.eq(Order.Status.NEW)
    .findList();