Sunday, 10 December 2023

Active Record pattern in Java with an example

The active record pattern is an architectural pattern, commonly used in object-relational mapping (ORM) frameworks. It aims to bridge the gap between object-oriented programming and relational databases by representing database tables as classes and table rows as objects.

The pattern provides an easy-to-use API for database operations, allowing developers to interact with the database using objects.

 

Here's a basic example of how the active record pattern works in Java.

 


User.java

package com.sample.app.entity;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import com.sample.app.util.DBConnectionUtil;

// Active Record class representing a "User" table in the database
public class User {
	private static boolean USER_TABLE_CREATED = false;
	private static AtomicInteger ID_COUNTER = new AtomicInteger(0);

	private Integer id;
	private String username;
	private String email;

	// Constructor
	public User(int id, String username, String email) {
		this.id = id;
		this.username = username;
		this.email = email;
	}

	public User(String username, String email) {
		this.username = username;
		this.email = email;
	}

	// Getters and setters

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	// Save method to insert or update the record in the database
	public static User save(User user) {
		Integer newId = user.id;
		try (Connection connection = DBConnectionUtil.connection()) {
			if (user.id == null) {
				// Insert new record
				newId = ID_COUNTER.incrementAndGet();
				String insertQuery = "INSERT INTO users (id, username, email) VALUES (?, ?, ?)";
				try (PreparedStatement preparedStatement = connection.prepareStatement(insertQuery)) {
					preparedStatement.setInt(1, newId);
					preparedStatement.setString(2, user.getUsername());
					preparedStatement.setString(3, user.getEmail());
					preparedStatement.executeUpdate();
				}
			} else {
				// Update existing record
				String updateQuery = "UPDATE users SET username = ?, email = ? WHERE id = ?";
				try (PreparedStatement preparedStatement = connection.prepareStatement(updateQuery)) {
					preparedStatement.setString(1, user.getUsername());
					preparedStatement.setString(2, user.getEmail());
					preparedStatement.setInt(3, user.getId());
					preparedStatement.executeUpdate();
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return find(newId);
	}

	// Find method to retrieve a record by ID from the database
	public static User find(int id) {
		try (Connection connection = DBConnectionUtil.connection()) {
			String selectQuery = "SELECT * FROM users WHERE id = ?";
			try (PreparedStatement preparedStatement = connection.prepareStatement(selectQuery)) {
				preparedStatement.setInt(1, id);
				try (ResultSet resultSet = preparedStatement.executeQuery()) {
					if (resultSet.next()) {
						// Map database columns to object properties
						String username = resultSet.getString("username");
						String email = resultSet.getString("email");
						// Return a new User object
						return new User(id, username, email);
					}
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}

	// Delete method to remove the record from the database
	public static void delete(User user) {
		try (Connection connection = DBConnectionUtil.connection()) {
			String deleteQuery = "DELETE FROM users WHERE id = ?";
			try (PreparedStatement preparedStatement = connection.prepareStatement(deleteQuery)) {
				preparedStatement.setInt(1, user.getId());
				preparedStatement.executeUpdate();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	public static List<User> all() {
		List<User> users = new ArrayList<>();
		try (Connection connection = DBConnectionUtil.connection()) {
			String deleteQuery = "SELECT * FROM users";
			try (PreparedStatement preparedStatement = connection.prepareStatement(deleteQuery)) {
				try (ResultSet resultSet = preparedStatement.executeQuery()) {
					if (resultSet.next()) {
						// Map database columns to object properties
						String username = resultSet.getString("username");
						String email = resultSet.getString("email");
						Integer id = resultSet.getInt("id");
						// Return a new User object
						users.add(new User(id, username, email));
					}
				}
			}

		} catch (SQLException e) {
			e.printStackTrace();
		}
		return users;
	}

	public static void createUserTable() {
		if (USER_TABLE_CREATED) {
			return;
		}

		try (Connection connection = DBConnectionUtil.connection()) {
			String createTable = "CREATE TABLE users (id int, username varchar(50), email varchar(100), PRIMARY KEY(id))";
			try (PreparedStatement preparedStatement = connection.prepareStatement(createTable)) {
				preparedStatement.execute();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", email=" + email + "]";
	}

}

In this example, the User class represents a user in a database with properties like id, username, and email. The class includes methods such as save, find, delete and all to perform database operations using JDBC. This example uses a simple H2 database connection, but you can adapt it to work with other databases or use an ORM (Object-Relational Mapping) library for more advanced features.

 

DBConnectionUtil.java

package com.sample.app.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DBConnectionUtil {

	public static Connection connection() throws SQLException {
		return DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", "");
	}

}

App.java

package com.sample.app;

import java.util.List;

import com.sample.app.entity.User;

public class App {
	// Example usage
	public static void main(String[] args) {
		// 1. Create users table
		User.createUserTable();

		// Persist new users
		User newUser1 = new User("Krishna", "krishna@example.com");
		User newUser2 = new User("ptr", "ptr@example.com");
		User newUser3 = new User("ram", "ram@example.com");

		// Save users
		User.save(newUser1);
		User.save(newUser2);
		User.save(newUser3);

		List<User> allUsers = User.all();
		System.out.println("\nAll the users :");
		allUsers.stream().forEach(System.out::println);

		// Retrieve the user by ID 1
		User retrievedUser = User.find(1);
		System.out.println("\nUser details for the id 1 is : " + retrievedUser);

		System.out.println("\nUpdate the user email and username with id 1");
		retrievedUser.setUsername("Joel");
		retrievedUser.setEmail("joel@example.com");
		User.save(retrievedUser);

		retrievedUser = User.find(1);
		System.out.println("\nUser details for the id 1 is : " + retrievedUser);

		System.out.println("\nDelete the user with id 1");
		User.delete(retrievedUser);

		allUsers = User.all();
		System.out.println("All the users :");
		allUsers.stream().forEach(System.out::println);

	}
}

Output

All the users :
User [id=1, username=Krishna, email=krishna@example.com]

User details for the id 1 is : User [id=1, username=Krishna, email=krishna@example.com]

Update the user email and username with id 1

User details for the id 1 is : User [id=1, username=Joel, email=joel@example.com]

Delete the user with id 1
All the users :
User [id=2, username=ptr, email=ptr@example.com]

Note

Because the data and the database access methods are in the same file, those files end up being bigger.

 

You can download this example from this link.


  

You may like

No comments:

Post a Comment