PojoQuery Examples
This page provides practical examples of using PojoQuery.
Example 1: Basic Select
Fetch all users ordered by last name.
POJO:
@Table("user")
public class User {
@Id Long id;
String firstName;
String lastName;
String email;
// Getters and setters omitted for brevity
}
Query:
List<User> users = PojoQuery.build(User.class)
.addOrderBy("user.lastName ASC")
.execute(dataSource);
Example 2: Select with Join
Fetch an article including its author details.
POJOs:
@Table("article")
public class Article {
@Id Long id;
String title;
// Getters and setters omitted for brevity
}
public class ArticleWithAuthor extends Article {
User author; // Automatically joins on 'author_id' column
// Getters and setters omitted for brevity
}
@Table("user")
public class User {
@Id Long id;
String firstName;
String lastName;
// Getters and setters omitted for brevity
}
Query:
ArticleWithAuthor article = PojoQuery.build(ArticleWithAuthor.class)
.addWhere("article.id = ?", 123L)
.execute(dataSource)
.stream().findFirst().orElse(null);
if (article != null) {
System.out.println("Author: " + article.getAuthor().getFirstName());
}
Example 3: One-to-Many Relationship
Fetch an article including a list of its comments.
POJOs:
@Table("article")
public class Article {
@Id Long id;
String title;
// Getters and setters omitted for brevity
}
public class ArticleWithComments extends Article {
List<Comment> comments; // Automatically joins on 'article_id' in comment table
// Getters and setters omitted for brevity
}
@Table("comment")
public class Comment {
@Id Long id;
String text;
Date submitDate;
// Getters and setters omitted for brevity
}
Query:
ArticleWithComments article = PojoQuery.build(ArticleWithComments.class)
.addWhere("article.id = ?", 456L)
.addOrderBy("comments.submitDate DESC") // Order comments
.execute(dataSource)
.stream().findFirst().orElse(null);
if (article != null) {
System.out.println("Comments count: " + article.getComments().size());
article.getComments().forEach(c -> System.out.println("- " + c.getText()));
}
Example 4: Aggregation (@GroupBy, @Select)
Get the count and latest comment date for each article.
POJO:
@Table("comment") // Query starts from comment table
@GroupBy("comment.article_id") // Group by article
public class ArticleCommentStats {
@FieldName("article_id") // Map the grouping key
Long articleId;
@Select("COUNT(*)")
Integer commentCount;
@Select("MAX(submitDate)")
Date lastCommentDate;
// Getters and setters omitted for brevity
}
Query:
List<ArticleCommentStats> stats = PojoQuery.build(ArticleCommentStats.class)
.execute(dataSource);
stats.forEach(s -> System.out.println(
"Article " + s.articleId + ": " + s.commentCount + " comments, last on " + s.lastCommentDate
));
Example 5: Custom SQL Field (@Select)
Fetch user with a calculated full name field.
POJO:
@Table("user")
public class UserWithFullName {
@Id Long id;
String firstName;
String lastName;
@Select("CONCAT(firstName, ' ', lastName)") // Database-specific function
String fullName;
// Getters and setters omitted for brevity
}
Query:
UserWithFullName user = PojoQuery.build(UserWithFullName.class)
.addWhere("user.id = ?", 789L)
.execute(dataSource)
.stream().findFirst().orElse(null);
if (user != null) {
System.out.println("Full Name: " + user.getFullName());
}
Example 6: Insert Operation
Insert a new user record.
POJO: (Same as Example 1)
Operation:
User newUser = new User();
newUser.setFirstName("Alice");
newUser.setLastName("Wonder");
newUser.setEmail("alice@example.com");
PojoQuery.insert(dataSource, newUser);
// newUser.getId() is now populated if it was auto-generated
System.out.println("New user ID: " + newUser.getId());
Example 7: Update Operation
Update an existing user’s email.
POJO: (Same as Example 1)
Operation:
// Assume 'userToUpdate' was fetched previously
userToUpdate.setEmail("alice.w@example.com");
int updatedRows = PojoQuery.update(dataSource, userToUpdate);
System.out.println("Rows updated: " + updatedRows);
Example 8: Many-to-Many Relationship
Fetch articles with their associated tags using a link table.
Database Schema:
-- article table
CREATE TABLE article (id BIGINT PRIMARY KEY, title VARCHAR(255));
-- tag table
CREATE TABLE tag (id BIGINT PRIMARY KEY, name VARCHAR(100));
-- link table (many-to-many)
CREATE TABLE article_tag (
article_id BIGINT REFERENCES article(id),
tag_id BIGINT REFERENCES tag(id),
PRIMARY KEY (article_id, tag_id)
);
POJOs:
@Table("article")
public class ArticleWithTags {
@Id Long id;
String title;
@Link(linktable = "article_tag", linkfield = "article_id", foreignlinkfield = "tag_id")
List<Tag> tags;
// Getters and setters omitted for brevity
}
@Table("tag")
public class Tag {
@Id Long id;
String name;
// Getters and setters omitted for brevity
}
Query:
List<ArticleWithTags> articles = PojoQuery.build(ArticleWithTags.class)
.execute(dataSource);
for (ArticleWithTags article : articles) {
System.out.println(article.getTitle() + " - Tags: " +
article.getTags().stream().map(Tag::getName).collect(Collectors.joining(", ")));
}
Example 9: Filtered Relationships with @JoinCondition
Fetch events with separate lists for visitors and organizers from the same person table.
Database Schema:
CREATE TABLE event (id BIGINT PRIMARY KEY, title VARCHAR(255));
CREATE TABLE person (id BIGINT PRIMARY KEY, firstname VARCHAR(100), lastname VARCHAR(100));
CREATE TABLE event_person (
event_id BIGINT,
person_id BIGINT,
role VARCHAR(20), -- 'visitor' or 'organizer'
PRIMARY KEY (event_id, person_id, role)
);
POJOs:
@Table("event")
public class EventWithParticipants {
@Id Long id;
String title;
@Link(linktable = "event_person", linkfield = "event_id", foreignlinkfield = "person_id")
@JoinCondition("{this}.id = {linktable}.event_id AND {linktable}.role = 'visitor'")
List<Person> visitors;
@Link(linktable = "event_person", linkfield = "event_id", foreignlinkfield = "person_id")
@JoinCondition("{this}.id = {linktable}.event_id AND {linktable}.role = 'organizer'")
List<Person> organizers;
// Getters and setters omitted for brevity
}
@Table("person")
public class Person {
@Id Long id;
String firstname;
String lastname;
// Getters and setters omitted for brevity
}
Query:
EventWithParticipants event = PojoQuery.build(EventWithParticipants.class)
.addWhere("event.id = ?", 1L)
.execute(dataSource)
.stream().findFirst().orElse(null);
if (event != null) {
System.out.println("Event: " + event.getTitle());
System.out.println("Visitors: " + event.getVisitors().size());
System.out.println("Organizers: " + event.getOrganizers().size());
}
Example 10: Embedded Objects
Map address fields from the same table into a nested object.
Database Schema:
CREATE TABLE customer (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
-- Shipping address columns with prefix
ship_street VARCHAR(255),
ship_city VARCHAR(100),
ship_zip VARCHAR(20),
-- Billing address columns with prefix
bill_street VARCHAR(255),
bill_city VARCHAR(100),
bill_zip VARCHAR(20)
);
POJOs:
// Value object (not an entity - no @Table)
public class Address {
String street;
String city;
String zip;
// Getters and setters omitted for brevity
}
@Table("customer")
public class Customer {
@Id Long id;
String name;
@Embedded(prefix = "ship_")
Address shippingAddress;
@Embedded(prefix = "bill_")
Address billingAddress;
// Getters and setters omitted for brevity
}
Query:
Customer customer = PojoQuery.build(Customer.class)
.addWhere("customer.id = ?", 100L)
.execute(dataSource)
.stream().findFirst().orElse(null);
if (customer != null) {
System.out.println("Ship to: " + customer.getShippingAddress().getCity());
System.out.println("Bill to: " + customer.getBillingAddress().getCity());
}
Example 11: Streaming Large Result Sets
Process millions of log entries without loading all into memory.
POJO:
@Table("access_log")
public class AccessLog {
@Id Long id;
String ipAddress;
String requestPath;
Integer statusCode;
LocalDate accessDate;
// Getters and setters omitted for brevity
}
Streaming Query:
LocalDate yesterday = LocalDate.now().minusDays(1);
// Using try-with-resources to ensure proper cleanup
try (Stream<AccessLog> stream = PojoQuery.build(AccessLog.class)
.addWhere("access_log.accessDate = ?", yesterday)
.executeStreaming(dataSource)
.stream()) {
// Count 404 errors without loading all rows
long notFoundCount = stream
.filter(log -> log.getStatusCode() == 404)
.count();
System.out.println("404 errors yesterday: " + notFoundCount);
}
// Alternative: process each row with a callback
DB.queryRowsStreaming(dataSource,
SqlExpression.sql("SELECT * FROM access_log WHERE status_code >= ?", 500),
row -> {
System.out.println("Error on path: " + row.get("request_path"));
});
Example 12: Handling Optional Relationships
Gracefully handle nullable foreign keys.
POJOs:
@Table("task")
public class Task {
@Id Long id;
String title;
User assignee; // Will be null if assignee_id is null (LEFT JOIN by default)
// Getters and setters omitted for brevity
}
@Table("user")
public class User {
@Id Long id;
String name;
// Getters and setters omitted for brevity
}
Query with Null Handling:
List<Task> tasks = PojoQuery.build(Task.class)
.execute(dataSource);
for (Task task : tasks) {
String assigneeName = task.getAssignee() != null
? task.getAssignee().getName()
: "Unassigned";
System.out.println(task.getTitle() + " - " + assigneeName);
}
// Query only unassigned tasks
List<Task> unassigned = PojoQuery.build(Task.class)
.addWhere("task.assignee_id IS NULL")
.execute(dataSource);
Example 13: Delete Operation
Delete a record by entity or by ID.
Operations:
// Delete by entity instance
User userToDelete = repo.findById(123L);
if (userToDelete != null) {
PojoQuery.delete(dataSource, userToDelete);
System.out.println("User deleted");
}
// Delete by ID directly (more efficient - no need to fetch first)
PojoQuery.deleteById(dataSource, User.class, 456L);
// Delete with raw SQL for bulk operations
int deleted = DB.update(dataSource,
SqlExpression.sql("DELETE FROM session WHERE last_activity < ?",
LocalDate.now().minusDays(30)));
System.out.println("Cleaned up " + deleted + " old sessions");
Example 14: Dynamic Columns with @Other
Handle tables with dynamic/schemaless column patterns.
Database Schema:
CREATE TABLE product (
id BIGINT PRIMARY KEY,
name VARCHAR(255),
-- Dynamic attribute columns with prefix
attr_color VARCHAR(50),
attr_size VARCHAR(20),
attr_weight DECIMAL(10,2),
attr_material VARCHAR(100)
);
POJO:
@Table("product")
public class Product {
@Id Long id;
String name;
// All columns starting with 'attr_' will be collected here
// Map keys will be 'color', 'size', 'weight', 'material' (without prefix)
@Other(prefix = "attr_")
Map<String, Object> attributes;
// Getters and setters omitted for brevity
}
Query:
Product product = PojoQuery.build(Product.class)
.addWhere("product.id = ?", 1L)
.execute(dataSource)
.stream().findFirst().orElse(null);
if (product != null) {
System.out.println("Product: " + product.getName());
System.out.println("Color: " + product.getAttributes().get("color"));
System.out.println("Size: " + product.getAttributes().get("size"));
// Iterate all dynamic attributes
product.getAttributes().forEach((key, value) ->
System.out.println(" " + key + ": " + value));
}