リレーションシップ


モデル間の関連はキーによって物理的に構成されます。ご存知の通り Key はタイプセーフではありません。 employee のキーを間違って department にセットすることもできてしまいます。 Slim3 はタイプセーフで便利な関連を提供します。

片方向1対1関連


2つのモデルの間の片方向1対1関連を作成します。

次の例では Employee モデルと Address モデルを定義しています。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

@Model
public class Address {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

では Employee に1対1関連の外部キーを追加しましょう。
ModelRef<ModelType> を使用して定義します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Address> addressRef;

    // ...
}

すると addressRef フィールドに次のようなエラーが表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'addressRef' の getter および setter を作成します」を選択します。

今度は setAddressRef メソッドに次のエラーが表示されます。
[SLIM3GEN1041] The setter method for the field[addressRef] is not allowed. Define the field as follows:
ModelRef<Address> addressRef = new ModelRef<Address>(Address.class);
(訳注:[addressRef]に対する setter メソッドは許可されていません。次のようにフィールドを定義してください:・・・)

メッセージの通りに addressRef フィールドを定義して setAddressRef メソッドを削除します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Address> addressRef = new ModelRef<Address>(Address.class);

    // ...
}


それでは employee と address を作成しましょう。
Address address = new Address();
...
Employee employee = new Employee();
...
employee.getAddressRef().setModel(address);
Datastore.put(address, employee);

これで employee と address を取得することができるようになりました。関連はレイジーにロードされます。
Key employeeKey = ...;
Employee employee = Datastore.get(Employee.class, employeeKey);
Address address = employee.getAddressRef().getModel();

双方向1対1関連


次の例では双方向1対1関連を定義します。

@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Address> addressRef = new ModelRef<Address>(Address.class);

    // ...
}

@Model
public class Address {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

今度は Address に1対1の逆向きの関連を追加しましょう。
InverseModelRef<ModelType, OwnerType> を使用して定義します。
@Model
public class Address {
    @Attribute(primaryKey = true)
    private Key key;

    private InverseModelRef<Employee, Address> employeeRef;

    // ...
}

すると employeeRef フィールドに次のようなエラーが表示されます。
[SILM3GEN1035] Specify @Attribute(persistent = false).
ModelRef has a key internally, so you need to persist it.
But this property is read only, so you do not need to persist it.
(訳注: @Attribute(persistent = false) を指定してください。
ModelRef はキーを内部に持っているので永続化する必要があります。
しかし、このプロパティはリードオンリーなので永続化する必要はありません。)

メッセージに従って次のように @Attribute(persistent = false) を定義します。
@Model
public class Address {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelRef<Employee, Address> employeeRef;

    // ...
}

今度は次のようなエラーが employeeRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'employeeRef' の getter および setter を作成します」を選択します。

次のようなエラーが setEmployeeRef メソッドに表示されます。
[SLIM3GEN1039] The setter method for the field[employeeRef] is not allowed. Define the field as follows:
InverseModelRef<Employee, Address> employeeRef =
  new InverseModelRef<Employee, Address>(Employee.class ,"xxx", this);
The 'xxx' means the mapped ModelRef<Address> property name in the class[Employee].

この場合 'xxx' は 'addressRef' です。
メッセージのとおりに、employeeRef フィールドを定義して 'xxx' の部分を 'addressRef' にします。
もし、GWTを使わないなら、'addressRef'のかわりに、EmployeeMeta.get().addressRef.getName() のようにタイプセーフに記述することもできます。
(訳注:Slim3+GWTはモデルをGWTクライアントでも使用することを想定している。モデルメタはGWTクライアントでは使用できないため、GWTクライアントで使用するモデル内ではモデルメタを使用することができない。)
@Model
public class Address {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelRef<Employee, Address> employeeRef =
        new InverseModelRef<Employee, Address>(Employee.class, "addressRef", this);

    // ...
}

そして setEmployeeRef  メソッドを削除します。


それでは employee と address を作成しましょう。
Address address = new Address();
...
Employee employee = new Employee();
...
employee.getAddressRef().setModel(address);
Datastore.put(address, employee);

これで employee と address を取得することができるようになりました。関連はレイジーにロードされます。
Key addressKey = ...;
Address address = Datastore.get(Address.class, addressKey);
Employee employee = address.getEmployeeRef().getModel();

片方向多対1関連


2つのモデルの間の片方向多対1関連を作成します。

次の例では Employee(多) モデルと Department(1) モデルを定義しています。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

では Employee に多対1関連の外部キーを追加しましょう。
ModelRef<ModelType> を使用して定義します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Department> departmentRef;

    // ...
}

すると departmentRef フィールドに次のエラーが表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'departmentRef' の getter および setter を作成します」を選択します。

次のようなエラーが setDepartmentRef メソッドに表示されます。
[SLIM3GEN1041] The setter method for the field[departmentRef] is not allowed. Define the field as follows:
ModelRef<Department> departmentRef = new ModelRef<Department>(Department.class);

メッセージの通りに addressRef フィールドを定義して setDepartmentRef を削除します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Department> departmentRef = new ModelRef<Department>(Department.class);
    // ...
}


それでは employee と department を作成しましょう。
Department department = new Department();
...
Employee employee = new Employee();
...
employee.getDepartmentRef().setModel(department);
Datastore.put(department, employee);

これで employee と department を取得することができるようになりました。関連はレイジーにロードされます。
Key employeeKey = ...;
Employee employee = Datastore.get(Employee.class, employeeKey);
Department department = employee.getDepartmentRef().getModel();

双方向1対多関連


次の例では双方向1対多関連を定義します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Department> departmentRef =
        new ModelRef<Department>(Department.class);

    // ...
}

@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

今度は Department に1対多の逆向きの関連を追加しましょう。
InverseModelListRef<ModelType, OwnerType> を使用して定義します。
@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    private InverseModelListRef<Employee, Department> employeeListRef;

    // ...
}

すると employeeListRef フィールドに次のようなエラーが表示されます。
[SLIM3GEN1035] Specify @Attribute(persistent = false).
ModelRef has a key internally, so you need to persist it.
But this property is read only, so you do not need to persist it.

メッセージに従って次のように @Attribute(persistent = false) を定義します。
@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelListRef<Employee, Department> employeeListRef;

    // ...
}

今度は次のようなエラーが employeeListRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'departmentRef' の getter および setter を作成します」を選択します。

次のようなエラーが setEmployeeListRef  メソッドに表示されます。
[SLIM3GEN1039] The setter method for the field[employeeListRef] is not allowed. Define the field as follows:
InverseModelListRef<Employee, Department> employeeListRef =
  new InverseModelListRef<Employee, Department>(Employee.class, "xxx", this);
The 'xxx' means the mapped ModelRef<Department> property name in the class[Employee].

この場合 'xxx' は 'departmentRef' です。
setEmployeeListRef メソッドを削除し、メッセージの通りに employeeListRef フィールドを定義して 'xxx' を 'departmentRef' にします。
もし、GWTを使わないなら、'departmentRef'のかわりに、EmployeeMeta.get().departmentRef.getName() のようにタイプセーフに記述することもできます。
@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelListRef<Employee, Department> employeeListRef =
        new InverseModelListRef<Employee, Department>(Employee.class, "departmentRef", this);

    // ...
}

ソート順は次のように指定できます。
@Model
public class Department {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelListRef<Employee, Department> employeeListRef =
        new InverseModelListRef<Employee, Department>(Employee.class, "departmentRef", this,
            new Sort("salary", SortDirection.DESCENDING));

    // ...
}

もし、GWTを使わないなら、'salary'のかわりに、EmployeeMeta.get().salary.getName() のようにタイプセーフに記述することもできます。

それでは employees と department を作成しましょう。
Department department = new Department();
...
Employee employee = new Employee();
Employee employee2 = new Employee();
...
employee.getDepartmentRef().setModel(department);
employee2.getDepartmentRef().setModel(department);
Datastore.put(department, employee, employee2);

これで department と employees  を取得することができるようになりました。関連はレイジーにロードされます。
Key departmentKey = ...;
Department department = Datastore.get(Department.class, departmentKey);
List<Employee> employeeList = department.getEmployeeListRef().getModelList();

双方向多対多関連 


3つのモデルの間の双方向多対多関連を作成します。

次の例ではEmployeeモデル(多側)、EmployeeProjectモデル(結合側)、Projectモデル(多側)を定義します。

Employee:
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

EmployeeProject:
@Model
public class EmployeeProject {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

Project:
@Model
public class Project {
    @Attribute(primaryKey = true)
    private Key key;

    // ...
}

それでは多対1関連の外部キーを EmployeeProject に追加しましょう。
ModelRef<ModelType> を使用して定義します。
@Model
public class EmployeeProject {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Employee> employeeRef;

    // ...
}

次のエラーが employeeRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'employeeRef'の getter および setter を作成します」を選択します。
次のエラーが setEmployeeRef メソッドに表示されます。
[SLIM3GEN1041] The setter method for the field[employeeRef] is not allowed. Define the field as follows:
ModelRef<Employee> employeeRef = new ModelRef<Employee>(Employee.class);

メッセージの通りに employeeRef フィールドを定義し setEmployeeRef メソッドを削除します。
@Model
public class EmployeeProject {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Employee> employeeRef = new ModelRef<Employee>(Employee.class);
    // ...
}

それでは逆向きの1対多関連を Employee に追加しましょう。
InverseModelListRef<ModelType, OwnerType> を使用します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    private InverseModelListRef<EmployeeProject, Employee> employeeProjectListRef;

    // ...
}

次のエラーが employeeProjectListRef フィールドに表示されます。
[SLIM3GEN1035] Specify @Attribute(persistent = false).
ModelRef has a key internally, so you need to persist it.
But this property is read only, so you do not need to persist it.

メッセージの通り、次のように @Attribute(persistent = false) を定義します。
@Model
public class Employee {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelListRef<EmployeeProject, Employee> employeeProjectListRef;

    // ...
}

次のエラーが employeeProjectListRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'employeeProjectListRef'の getter および setter を作成します」を選択します。
次のエラーが setEmployeeProjectListRef メソッドに表示されます。
[SLIM3GEN1039] The setter method for the  field[employeeProjectListRef] is not allowed. Define the field as  follows:
InverseModelListRef<EmployeeProject, Employee> employeeProjectListRef =
  new  InverseModelListRef<EmployeeProject, Employee>(EmployeeProject.class, "xxx",  this);
The 'xxx' means the mapped  ModelRef<Employee> property name in the  class[EmployeeProject].

この場合 'xxx' は 'employeeRef' です。
メッセージの通りに、employeeProjectListRef フィールドを定義し 'xxx' を 'employeeRef' に置き換えます。
もしGWTを使用していないなら、"employeeRef" という文字列の代わりに EmployeeProjectMeta.get().employeeRef.getName() のようにタイプセーフに記述することもできます。
@Model
public  class  Employee {
     @Attribute(primaryKey =  true)
     private  Key  key;

     @Attribute(persistent = false)
    private  InverseModelListRef<EmployeeProject, Employee>  employeeProjectListRef =
        new  InverseModelListRef<EmployeeProject, Employee>(EmployeeProject.class,  "employeeRef", this);

     //  ...
}

そして setEmployeeProjectListRef メソッドを削除します。

さて、次は多対1関連の外部キーを EmployeeProject に追加しましょう。
ModelRef<ModelType> を使用します。
@Model
public class EmployeeProject {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Employee> employeeRef;

    private ModelRef<Project> projectRef;
    // ...
}

次のエラーが projectRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'projectRef'の getter および setter を作成します」を選択します。
次のエラーが setProjectRef メソッドに表示されます。
[SLIM3GEN1041] The setter method for the field[projectRef] is not allowed. Define the field as follows:
ModelRef<Project> projectRef = new ModelRef<Project>(Project.class);

メッセージの通りに projectRef フィールドを定義し setProjectRef メソッドを削除します。
@Model
public class EmployeeProject {
    @Attribute(primaryKey = true)
    private Key key;

    private ModelRef<Employee> employeeRef = new ModelRef<Employee>(Employee.class);

    private ModelRef<Project> projectRef = new ModelRef<Project>(Project.class);
    // ...
}

それでは逆向きの1対多関連を Project に追加しましょう。
InverseModelListRef<ModelType, OwnerType> を使用します。
@Model
public class Project {
    @Attribute(primaryKey = true)
    private Key key;

    private InverseModelListRef<EmployeeProject, project> employeeProjectListRef;

    // ...
}

次のエラーが employeeProjectListRef フィールドに表示されます。
[SLIM3GEN1035] Specify @Attribute(persistent = false).
ModelRef has a key internally, so you need to persist it.
But this property is read only, so you do not need to persist it.

メッセージの通り、次のように @Attribute(persistent = false) を定義します。
@Model
public class Project {
    @Attribute(primaryKey = true)
    private Key key;

    @Attribute(persistent = false)
    private InverseModelListRef<EmployeeProject, Project> employeeProjectListRef;

    // ...
}

次のエラーが employeeProjectListRef フィールドに表示されます。
[SLIM3GEN1011] The getter method is not found.

クイックフィックス(CTRL + 1)を使用して「'employeeProjectListRef'の getter および setter を作成します」を選択します。
次のエラーが setEmployeeProjectListRef メソッドに表示されます。
[SLIM3GEN1039] The setter method for the  field[employeeProjectListRef] is not allowed. Define the field as  follows:
InverseModelListRef<EmployeeProject, Project> employeeProjectListRef =
  new  InverseModelListRef<EmployeeProject, Project>(EmployeeProject.class, "xxx",  this);
The 'xxx' means the mapped  ModelRef<Project> property name in the  class[EmployeeProject].

この場合 'xxx' は 'projectRef' です。
メッセージの通りに、employeeProjectListRef フィールドを定義し 'xxx' を 'projectRef' に置き換えます。
もしGWTを使用していないなら、"employeeRef" という文字列の代わりに EmployeeProjectMeta.get().projectRef.getName() のようにタイプセーフに記述することもできます。
@Model
public class Project {
    @Attribute(primaryKey =  true)
    private  Key  key;

    @Attribute(persistent = false)
    private  InverseModelListRef<EmployeeProject, Project>  employeeProjectListRef =
        new  InverseModelListRef<EmployeeProject, Project>(EmployeeProject.class,  "projectRef", this);

     //  ...
}

そして setEmployeeProjectListRef メソッドを削除します。

それでは employee、employee-project、project を作成しましょう。
Employee employee1 = new Employee();
Employee employee2 =  new Employee();

Project project1 =  new Project();
Project project2 =  new Project();

EmployeeProject employeeProject11 = new EmployeeProject();
employeeProject11.getEmployeeRef().setModel(employee1);
employeeProject11.getProjectRef().setModel(project1);

EmployeeProject employeeProject12 = new EmployeeProject();
employeeProject12.getEmployeeRef().setModel(employee1);
employeeProject12.getProjectRef().setModel(project2);

EmployeeProject employeeProject21 = new EmployeeProject();
employeeProject21.getEmployeeRef().setModel(employee2);
employeeProject21.getProjectRef().setModel(project1);
 
EmployeeProject employeeProject22 = new EmployeeProject();
employeeProject22.getEmployeeRef().setModel(employee2);
employeeProject22.getProjectRef().setModel(project2);

Datastore.put(employee1, employee2, project1, project2,
    employeeProject11, employeeProject12, employeeProject21, employeeProject22);

これで employee や project を取得することができます。関連はレイジーにロードされます。
Key employeeKey = ...;
Employee employee = Datastore.get(Employee.class, employeeKey);
for (EmployeeProject ep : employee.getEmployeeProjectRef().getModelList()) {
    Project project = ep.getProjectRef().getModel();
    ...
}

Key projectKey = ...;
Project project =  Datastore.get(Project.class, projectKey);
for (EmployeeProject ep : project.getEmployeeProjectRef().getModelList()) {
    Employee employee = ep.getEmployeeRef().getModel();
    ...
}