This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Join Fetch

Filter related entities while selecting specific columns

    In a POJO, you can use @JoinFetch on a field or class to filter associated entities. The difference from @Join is that this allows fetching all lazy-related data at once.

    Single Join Fetch

    For example, consider a Customer entity that has a one-to-many relationship with an Order entity:

    @Entity class Customer { @OneToMany(fetch = LAZY, cascade = ALL) @JoinColumn(name = "order_id") private Collection<Order> orders; } @Entity class Order { private String itemName; }

    If you want to fetch Order data when retrieving Customer, you can do:

    @Data @JoinFetch(path = "orders") class CustomerOrderCriteria { @Spec String name; }

    The executed SQL will be like:

    select distinct customer0_.* ..., orders1_.* ... from customer customer0_ inner outer join orders orders1_ on customer0_.id=orders1_.order_id where customer0_.name=?

    You can see that orders1_.* is also included in the select fields.

    Join Behavior

    To better align with most usage scenarios, the default behavior is as follows:

    • The default join type is INNER.
    • Duplicate results are removed (distinct).

    You can modify the default behavior by configuring @JoinFetch#joinType or @JoinFetch#distinct, for example:

    @JoinFetch(joinType = JoinType.RIGHT, distinct = false)

    With Clause

    @JoinFetch also allows filtering data. For example, if you want to filter both customer names and order names, define a POJO as follows:

    @Data @JoinFetch(path = "orders", alias = "o") public class CustomerOrderCriteria { @Spec String name; @Spec(path = "o.itemName", value = In.class) Collection<String> items; }

    The executed SQL will be like:

    select distinct customer0_.* ..., orders1_.* ... from customer customer0_ inner outer join orders orders1_ on customer0_.id=orders1_.order_id where customer0_.name=? and orders1_.item_name in (?)

    @JoinFetch can also be used at the field level, for example:

    @Data public class CustomerOrderCriteria { @Spec String name; @JoinFetch(path = "orders", alias = "o") @Spec(path = "o.itemName", value = In.class) Collection<String> items; }

    Multi Join Fetches

    You can use @JoinFetches to define multi-level fetches. For example, if the Order entity has a many-to-many relationship with a Tag entity:

    @Entity class Customer { @OneToMany(cascade = ALL, fetch = LAZY) @JoinColumn(name = "order_id") private Set<Order> orders; } @Entity class Order { @ManyToMany(cascade = ALL, fetch = LAZY) private Set<Tag> tags; } @Entity class Tag { private String name; }

    If you want to query customers who purchased items belonging to specific categories, define a POJO as follows:

    @Data class CustomerOrderTagCriteria { @JoinFetches({ @JoinFetch(path = "orders", alias = "o"), @JoinFetch(path = "o.tags", alias = "t") }) @Spec(path = "t.name", value = In.class) Collection<String> tags; }

    The executed SQL will be like:

    select distinct customer0_.* ..., orders1_.* ..., tag3_.* ... from customer customer0_ inner join orders orders1_ on customer0_.id=orders1_.order_id inner join orders_tags tags2_ on orders1_.id=tags2_.order_id inner join tag tag3_ on tags2_.tags_id=tag3_.id where tag3_.name in (?)

    @JoinFetches can also be used at the class level, making the aliases available across fields in the same object. For example:

    @Data @JoinFetches({ @JoinFetch(path = "orders", alias = "o"), @JoinFetch(path = "o.tags", alias = "t") }) public class CustomerOrderCriteria { @Spec(path = "o.itemName", value = In.class) Collection<String> items; @Spec(path = "t.name", value = In.class) Collection<String> tags; }

    Fetches Order

    Annotations are processed in order, so @JoinFetches must be defined in the correct sequence.

    For example, in the previous scenario, the following order is incorrect:

    @Data class CustomerOrderTagCriteria { @JoinFetches({ @JoinFetch(path = "o.tags", alias = "t"), // "o" alias will be not exist during processing this @Join @JoinFetch(path = "orders", alias = "o") }) @Spec(path = "t.name", value = In.class) Collection<String> tagNames; }

    Alias

    The usage rules for @JoinFetch#alias are as follows:

    • It is shared within the same POJO
    • It cannot be declared multiple times within the same POJO
    • If not provided, the default alias is @JoinFetch#path
    • If it contains ., it will be replaced with _

    For example:

    @JoinFetches({ @JoinFetch(path = "orders"), // default alias is "orders" @JoinFetch(path = "orders.tags") // default alias is "orders_tags" }) @Spec(path = "orders_tags.name", value = In.class)