Slim3 Datastore‎ > ‎Relationships‎ > ‎

Bidirectional Many-to-Many Relationships

You create a bidirectional many-to-many relationship between three models.

The following example defines an Employee(many side) model, an EmployeeProject(junction side) and a Project(many side) model:

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;

   
// ...
}

Let's add a many-to-one relationship with a foreign key to EmployeeProject.
To define it, use ModelRef<ModelType>.
@Model
public
class EmployeeProject {
   
@Attribute(primaryKey = true)
   
private Key key;

private ModelRef<Employee> employeeRef;

   
// ...
}

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

Use quick fix(hold down CTRL+1) and select "Create getter and setter for 'employeeRef'".

The following error will be shown for setEmployeeRef method:
[SLIM3GEN1041] The setter method for the field[employeeRef] is not allowed. Define the field as follows:
ModelRef<Employee> employeeRef = new ModelRef<Employee>(Employee.class);

As the message says, define employeeRef field and delete setEmployeeRef method.
@Model
public
class EmployeeProject {
   
@Attribute(primaryKey = true)
   
private Key key;

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

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

private InverseModelListRef<EmployeeProject, Employee> employeeProjectListRef;

   
// ...
}

The following error will be shown for employeeProjectListRef 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 Employee {
   
@Attribute(primaryKey = true)
   
private Key key;

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

   
// ...
}

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

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

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

   
// ...
}

Then delete setEmployeeProjectListRef method.

Let's add a many-to-one relationship with a foreign key to EmployeeProject.
To define it, use ModelRef<ModelType>.
@Model
public
class EmployeeProject {
   
@Attribute(primaryKey = true)
   
private Key key;

private ModelRef<Employee> employeeRef;

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

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

Use quick fix(hold down CTRL+1) and select "Create getter and setter for 'projectRef'".

The following error will be shown for setProjectRef method:
[SLIM3GEN1041] The setter method for the field[projectRef] is not allowed. Define the field as follows:
ModelRef<Project> projectRef = new ModelRef<Project>(Project.class);

As the message says, define projectRef field and delete setProjectRef method.
@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);
   
// ...
}

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

private InverseModelListRef<EmployeeProject, project> employeeProjectListRef;

   
// ...
}

The following error will be shown for employeeProjectListRef 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 Project {
   
@Attribute(primaryKey = true)
   
private Key key;

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

   
// ...
}

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

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

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

   
// ...
}

Then delete setEmployeeProjectListRef method.

Now let's create employees, employee-projects and projects.
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);


You can get employees and projects. The relationship is loaded lazily.
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();
    ...
}


Next...

Continue to Polymorphic Model.


Comments