Slim3 Datastore‎ > ‎Relationships‎ > ‎

Bidirectional One-to-Many Relationships

The following example defines a unidirectional many-to-one relationship:

@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;

   
// ...
}

Let's add an inverse one-to-many relationship to Department.
To define it, use InverseModelListRef<ModelType, OwnerType>.
@Model
public
class Department {
   
@Attribute(primaryKey = true)
   
private Key key;

private InverseModelListRef<Employee, Department> employeeListRef;

   
// ...
}

The following error will be shown for employeeListRef field:
[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.

As the message says, define @Attribute(persistent = false) as follows:
@Model
public
class Department {
   
@Attribute(primaryKey = true)
   
private Key key;

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

   
// ...
}

The following error will be shown for employeeListRef field:
[SLIM3GEN1011] The getter method is not found.

Use quick fix(hold down CTRL+1) and select "Create getter and setter for 'employeeListRef'".
The following error will be shown for setEmployeeListRef method:
[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].

In this case, 'xxx' is 'departmentRef'.
As the message says, define employeeListRef field and replace 'xxx' with 'departmentRef'. If you do not use GWT, you can use EmployeeMeta.get().departmentRef.getName() type-safely instead of "departmentRef".
@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);

   
// ...
}


You can specify sort order as follows:
@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));

   
// ...
}

If you do not use GWT, you can use EmployeeMeta.get().salary.getName() type-safely instead of "salary".

Then delete setEmployeeListRef method.

Now let's create employees and a 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);

You can get a department and employees. The relationship is loaded lazily.
Key departmentKey = ...;
Department department = Datastore.get(Department.class, departmentKey);
List<Employee> employeeList = department.getEmployeeListRef().getModelList();

Comments