Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable mapping of arbitrary SQL results to aggregate entities #1274

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

nakamura-to
Copy link
Member

@nakamura-to nakamura-to commented Jan 26, 2025

Update the functionality to support mapping arbitrary SQL results to aggregate entities.

TODO

  • Rename the aggregateHelper element in the AssociationLinker annotation to aggregateStrategy.
  • Add a tableAlias element to the AssociationLinker annotation.
  • Make the columnPrefix element of the AssociationLinker annotation optional, and set its default value to the tableAlias value concatenated with an underscore.
  • Use the expand directive to generate column names and aliases.
  • Prohibit combinations with SelectType.STREAM and SelectType.COLLECT.
  • Remove dependencies on the Criteria API package.
  • Add tests.

Example

Below is an example that demonstrates the process:

Entity Classes

This example involves three entity classes. The Department and Employee entities have a bidirectional One-to-Many relationship, while the Employee and Address entities share a unidirectional One-to-One relationship. Fields representing these relationships are annotated with @Association.

@Entity
public class Department {
  @Association List<Employee> employeeList = new ArrayList<>();
  ...
}
@Entity
public class Employee {
  @Association Department department;
  @Association Address address;
  ...
}
@Entity
public class Address {
   ...
}

DAO

Pay attention to the aggregateStrategy specified in the DAO's @Select annotation. This strategy class is responsible for linking the entities. Fields in the strategy class annotated with @AssociationLinker define the relationships using BiFunction.

  • propertyPath: Specify the path from the root entity by chaining property names with dots.
  • columnPrefix: Specify the prefix for the SQL columns that map to the properties of the associated entity.

DepartmentDao.java

public interface DepartmentDao {

  @Select(aggregateStrategy = DepartmentStrategy.class)
  Department selectById(Integer departmentId);
}

interface DepartmentStrategy {
  @AssociationLinker(propertyPath = "employeeList", columnPrefix = "e_")
  BiFunction<Department, Employee, Department> employeeList =
      (d, e) -> {
        d.getEmployeeList().add(e);
        e.setDepartment(d);
        return d;
      };

  @AssociationLinker(propertyPath = "employeeList.address", columnPrefix = "a_")
  BiFunction<Employee, Address, Employee> employeeListAddress =
      (e, a) -> {
        e.setAddress(a);
        return e;
      };
}

SQL

The columnPrefix specified in @AssociationLinker is used to define column aliases in the SQL query.

selectById.sql

select
    d.department_id,
    d.department_no,
    d.department_name,
    d.location,
    d.version,
    e.employee_id as e_employee_id,
    e.employee_no as e_employee_no,
    e.employee_name as e_employee_name,
    e.manager_id as e_manager_id,
    e.hiredate as e_hiredate,
    e.salary as e_salary,
    e.department_id as e_department_id,
    e.address_id as e_address_id,
    a.address_id as a_address_id,
    a.street as a_street,
    a.version as a_version
from
    DEPARTMENT d
left outer join EMPLOYEE e
    on d.department_id = e.department_id
left outer join ADDRESS a
    on e.address_id = a.address_id
where
    d.department_id = /*departmentId*/0

Client

The DAO can be used in a straightforward manner. By calling the DAO method, you can retrieve an object that includes the aggregated entities.

@Test
public void test(Config config) {
  DepartmentDao dao = new DepartmentDaoImpl(config);
  Department department = dao.selectById(1);

  System.out.printf("department: %s%n", department.getDepartmentId());
  for (Employee employee : department.getEmployeeList()) {
    System.out.printf("employee: %s%n", employee.getEmployeeId());
    System.out.printf("employee.department: %s%n", employee.getDepartment().getDepartmentId());
    Address address = employee.getAddress();
    if (address != null) {
      System.out.printf("address: %s%n", address.getAddressId());
    }
  }
}

The term `aggregateHelper` was replaced with `aggregateStrategy` across the codebase to better reflect its purpose. This update includes variable, method, and class names, as well as documentation updates, ensuring consistency and improved code readability.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant