I have a Spring Data repository where I'm getting all positions for a set of accounts:
public interface PositionRepository extends JpaRepository<Position, PositionKey> {
@EntityGraph(value = "Position.all", type = EntityGraphType.LOAD)
List<Position> findByAccountIn(Set<Account> accounts);
}
Position has attributes that are also entities (a few nested levels):
@Entity
@NamedEntityGraph(name = "Position.all",
attributeNodes = {@NamedAttributeNode("account", subgraph = "Account.all"),
@NamedAttributeNode("product", subgraph = "Product.all")
})
@Data
public class Position {
@EmbeddedId
private PositionKey positionKey;
@MapsId("accountId")
@ManyToOne
@JoinColumn(name = "accountId")
private Account account;
@MapsId("productId")
@ManyToOne
@JoinColumn(name = "productId")
private Product product;
}
@Embeddable
@Data
public class PositionKey implements Serializable {
@Column(name = "accountId")
private Long accountId;
@Column(name = "productId")
private Long productId;
}
@Entity
@NamedEntityGraph(includeAllAttributes = true, name = "Product.all",
attributeNodes = {@NamedAttributeNode(value = "vendor", subgraph = "Vendor.all"),
@NamedAttributeNode(value = "type", subgraph = "ProductType.all")}
)
@Data
public class Product {
@Id
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "typeId")
private ProductType type;
@ManyToOne
@JoinColumn(name = "vendorCode")
private Vendor vendor;
}
@Entity
@NamedEntityGraph(name = "Account.all")
@Data
public class Account {
@Id
@Column(name = "accountId")
private Long id;
}
I'm always returning the full entity graph of positions as serialized JSON to a client. So, I'm always going to need all attributes and nested attributes. The position instances are 350 max.
Despite using @NamedEntityGraph, I noticed that individual queries are still being issued. For example, I get a query for each unique vendor. It usually takes ~2-3 seconds to get the results from all the individual queries.
How can I tell JPA to issue one query with multiple joins? I can manually write this SQL (using multiple joins) and it returns in just a few milliseconds.
Update
The data is accessed as follows:
@RestController
@RequestMapping("/position")
@RequiredArgsConstructor
public class PositionController {
private final PositionRepository positionRepo;
@GetMapping
public List<Position> getAllPositions(Set<Account> accounts) {
return positionRepo.findByAccountIn(account);
}
}
When the list of positions is returned, they are serialized via Jackson. So, it's Jackson that actually accesses the data.