Closed5

Domaで任意のSQLの実行結果を集約オブジェクトにマッピングさせる仕様案

nakamura_tonakamura_to

エンティティクラス

エンティティ間には、OneToMany、ManyToOne、OneToOneの関係性がある。
直接カラムにマッピングされないことを示すため、関連を表すプロパティには @Transient が必要。

@Entity
public class Department {
    private int id;
    private String name;
    @Transient
    private List<Employee> employees;
    // Getters and setters
}
@Entity
public class Employee {
    private int id;
    private String name;
    @Transient
    private Department department;
    @Transient
    private Address address;
    // Getters and setters
}
@Entity
public class Address {
    private int id;
    private String street;
    // Getters and setters
}

エンティティリンカー

新しく導入を考えている @EntityLinker@Association を利用したクラス。

@EntityLinker
public class DepartmentLinker {
    @Association(columnPrefix = "e_")
    public final BiFunction<Department, Employee, Department> employees = (d, e) -> {
        // 双方向の関連を持たせるかどうかは実装次第
        d.getEmployees().add(e);
        e.setDepartment(d);
        return d;
    };

    @Association(columnPrefix = "a_")
    public final BiFunction<Employee, Address, Employee> address = (e, a) -> {
        e.setAddress(a);
        return e;
    };
}

@EntityLinker を注釈されたクラスはエンティティ同士を関連づける役割を担う。@AssociationBiFunction の1番目の型パラメターが表すクラスから @Association が注釈されたフィールド名のプロパティを探し、2番目の型パラメーターを関連づけるということを表す。3番目の型パラメーターは必ず1番目の型パラメーターと同型とし、関連づけが終わった型を BiFunction の呼び出し元に返せるようにする。

@AssociationcolumnPrefix要素は、指定されたプレフィックスを持つカラムを2番目の型パラメータが表すエンティティクラスへマッピングすることを表す。

DAOインタフェース

@Selectのlinker要素は新しく導入を考えているもの。 エンティティリンカーを指定できるようにする。

@Dao
public interface DepartmentDao {
  @Sql("""
    SELECT 
        d.id,                         
        d.name,                    
        e.id AS e_id,            
        e.name AS e_name, 
        a.id AS a_id,            
        a.street AS a_street 
    FROM 
        department d
    LEFT JOIN 
        employee e ON d.id = e.department_id
    LEFT JOIN 
        address a ON e.address_id = a.id
    WHERE 
        d.id = /* id */0
  """)
  @Select(linker = DepartmentLinker.class)
  Department selectById(int id); 
}
nakamura_tonakamura_to

@Association を付与するフィールドの型について。ミュータブルなエンティティを対象にするなら BiConsumer でもよいが、 イミュータブルなエンティティに対応するために BiFunction にする。

nakamura_tonakamura_to

エンティティクラスを型にもつフィールドやエンティティクラスを要素とするコレクション型は、@Transientが注釈されているとみなす注釈処理オプションがあってもいいかもしれない。

nakamura_tonakamura_to
public interface DepartmentLinker {
    @EntityLinker(columnPrefix = "e_")
    BiFunction<Department, Employee, Department> employees = (d, e) -> {
        d.getEmployees().add(d);
        d.setEmployee(e);
        return d;
    };
}
public interface EmloyeeLinker {
    @EntityLinker(columnPrefix = "a_")
    BiFunction<Employee, Address, Employee> address = (e, a) -> {
        e.setAddress(a);
        return e;
    };
}

再利用性を考えると上のように定義して、呼び出し元で複数指定できるようにするのもありか。

  @Select(linkers = { DepartmentLinker.class, EmployeeLinker.class })
  Department selectById(int id); 

  @Select(linkers = { EmployeeLinker.class })
  List<Employee> selectEmployeesByDepartmentId(int departmentId); 
このスクラップは2025/02/11にクローズされました