Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/site/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ children:
url: todo-list-tutorial-repository.html
output: 'web, pdf'

- title: 'Add Model Relations'
url: todo-list-tutorial-relations.html
output: 'web, pdf'

- title: 'Add TodoList Controller'
url: todo-list-tutorial-controller.html
output: 'web, pdf'
Expand Down
60 changes: 2 additions & 58 deletions docs/site/tutorials/todo-list/todo-list-tutorial-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ Enter an empty property name when done

? Enter the property name: id
? Property type: number
? Is ID field? Yes
? Required?: No
? Default value [leave blank for none]:
? Is id the ID property? Yes
? Is id generated automatically? Yes

Let's add another property to TodoList
Enter an empty property name when done
Expand Down Expand Up @@ -70,61 +69,6 @@ Enter an empty property name when done
Model TodoList was created in src/models/
```

Now that we have our new model, we need to define its relation with the `Todo`
model. Add the following import statements and property to the `TodoList` model
and update the `TodoListRelations` interface to include `todos`:

{% include code-caption.html content="src/models/todo-list.model.ts" %}

```ts
import {hasMany} from '@loopback/repository';
import {Todo, TodoWithRelations} from './todo.model';

@model()
export class TodoList extends Entity {
// ...properties defined by the CLI...

@hasMany(() => Todo)
todos?: Todo[];

// ...constructor def...
}

export interface TodoListRelations {
todos?: TodoWithRelations[];
}

export type TodoListWithRelations = TodoList & TodoListRelations;
```

The `@hasMany()` decorator defines this property. As the decorator's name
suggests, `@hasMany()` informs LoopBack 4 that a todo list can have many todo
items.

To complement `TodoList`'s relationship to `Todo`, we'll add in the `todoListId`
property on the `Todo` model to define the relation on both ends, along with
updating the `TodoRelations` interface to include `todoList`:

{% include code-caption.html content="src/models/todo.model.ts" %}

```ts
@model()
export class Todo extends Entity {
// ...properties defined by the CLI...

@belongsTo(() => TodoList)
todoListId: number;

// ...constructor def...
}

export interface TodoRelations {
todoList?: TodoListWithRelations;
}

export type TodoWithRelations = Todo & TodoRelations;
```

Once the models have been completely configured, it's time to move on to adding
a [repository](todo-list-tutorial-repository.md) for `TodoList`.

Expand Down
155 changes: 155 additions & 0 deletions docs/site/tutorials/todo-list/todo-list-tutorial-relations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
---
lang: en
title: 'Add Model Relations'
keywords: LoopBack 4.0, LoopBack 4
sidebar: lb4_sidebar
permalink: /doc/en/lb4/todo-list-tutorial-relations.html
summary: LoopBack 4 TodoList Application Tutorial - Add TodoList Repository
---

### Define the model relation

We are going to add the model relation to indicate the relation that `TodoList`
_hasMany_ `Todo` using the
[`lb4 relation` command](https://loopback.io/doc/en/lb4/Relation-generator.html).

```sh
$ lb4 relation
? Please select the relation type hasMany
? Please select source model TodoList
? Please select target model Todo
? Foreign key name to define on the target model todoListId
? Source property name for the relation getter todos
? Allow TodoList queries to include data from related Todo instances? Yes
create src/controllers/todo-list-todo.controller.ts

Relation HasMany was created in src/
```

Now, we're going to add the relation for `Todo`. That is, `Todo` _belongsTo_
`TodoList`.

```sh
$ lb4 relation
? Please select the relation type belongsTo
? Please select source model Todo
? Please select target model TodoList
? Source property name for the relation getter todoListId
? Allow Todo queries to include data from related TodoList instances? Yes
create src/controllers/todo-todo-list.controller.ts

Relation BelongsTo was created in src/
```

{% include note.html content="
we use **default** foreign key and source property names in this case.
If you'd like to customize them, please check `Relation Metadata`
https://loopback.io/doc/en/lb4/HasMany-relation.html#relation-metadata and other
relations as well.
" %}

### Behind the scene

If you want to understand the code changes introduced from the relation
generator command, read on the details in this section; otherwise, you are ready
to move to the next step to create the controller.

#### Relation decorators

When we added the `hasMany` relation using the `lb4 relation` command, it added
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we added the hasMany relation using the lb4 relation command, it added
@hasMany() decorator defines this property

When we added the hasMany relation using the lb4 relation command, it added the
@hasMany() decorator which defines this property . (Is this what we want to say?)

Copy link
Member Author

@dhmlau dhmlau Nov 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, it added the property + the decorator. How about:

When we added the hasMany relation using the lb4 relation command, it added the
@hasMany() decorator together with the todo property.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, it added the property + the decorator. How about:

When we added the hasMany relation using the lb4 relation command, it added the
@hasMany() decorator together with the todo property.

todo or todos ? The line below says:

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we still need a the before '@hasmany decorator'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be todos property (the one in the documentation is correct).

OK. how about this:

When we added the hasMany relation using the lb4 relation command, it added
the @hasMany() decorator together with the todos property.

the `@hasMany()` decorator together with the `todos` property. As the
decorator's name suggests, `@hasMany()` informs LoopBack 4 that a todo list can
have many todo items.

```ts
export class TodoList extends Entity {
// ...properties defined by the CLI...

@hasMany(() => Todo)
todos?: Todo[];

// ...constructor def...
}
```

Similarly for the `belongsTo` relation:

```ts
export class Todo extends Entity {
// ...properties of the Todo model

@belongsTo(() => TodoList)
todoListId: number;

// ...constructor def...
}
```

#### Inclusion of Related Models

When we ran the `lb4 relation` command, we accepted the default of `Yes` to the
prompt:

```sh
? Allow Order queries to include data from related Customer instances? (Y/n)
```

This registers the `inclusionResolver` for the relation(s) you were working with
above.

Make sure to choose ‘yes’ if you’d like to use inclusion and your model is
traversable. In the example of getting the related `Todo` objects for each
`TodoList`, it registers the inclusion resolver that comes with the
[`HasManyRepositoryFactory`](https://loopback.io/doc/en/lb4/apidocs.repository.hasmanyrepository.html).

Let's take a closer look at the `TodoListRepository`.
{% include code-caption.html content="src/repositories/todo-list.repository.ts" %}

```ts
this.todos = this.createHasManyRepositoryFactoryFor(
'todos',
todoRepositoryGetter,
);
// this line enables inclusion for this relation
this.registerInclusionResolver('todos', this.todos.inclusionResolver);
```

As a result, when you get a `TodoList`, a `todos` property will be included that
contains your related `Todo`s, for example:

```json
{
"id": 2,
"title": "My daily chores",
"todos": [
{
"id": 3,
"title": "play space invaders",
"desc": "Become the very best!",
"todoListId": 2
}
]
}
```

On the other end,
[`BelongsToAccessor`](https://loopback.io/doc/en/lb4/apidocs.repository.belongstoaccessor.html)
also comes with an inclusion resolver function that we can register on the
`TodoRepository`.

{% include code-caption.html content="src/repositories/todo.repository.ts" %}

```ts
this.todoList = this.createBelongsToAccessorFor(
'todoList',
todoListRepositoryGetter,
);
// this line enables inclusion for this relation
this.registerInclusionResolver('todoList', this.todoList.inclusionResolver);
```

### Navigation

Previous step: [Add TodoList Repository](todo-list-tutorial-repository.md)

Last step: [Add TodoList Controller](todo-list-tutorial-controller.md)
109 changes: 1 addition & 108 deletions docs/site/tutorials/todo-list/todo-list-tutorial-repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,115 +37,8 @@ bridge)
Repository TodoListRepository was created in src/repositories/
```

From there, we'll need to make two more additions:

- define the `todos` property, which will be used to build a constrained
`TodoRepository`
- inject `TodoRepository` instance

Once the property type for `todos` has been defined, use
`this.createHasManyRepositoryFactoryFor` to assign it a repository constraining
factory function. Pass in the name of the relationship (`todos`) and the Todo
repository instance to constrain as the arguments for the function.

{% include code-caption.html content="src/repositories/todo-list.repository.ts" %}

```ts
import {Getter, inject} from '@loopback/core';
import {
DefaultCrudRepository,
HasManyRepositoryFactory,
juggler,
repository,
} from '@loopback/repository';
import {Todo, TodoList, TodoListRelations} from '../models';
import {TodoRepository} from './todo.repository';

export class TodoListRepository extends DefaultCrudRepository<
TodoList,
typeof TodoList.prototype.id,
TodoListRelations
> {
public readonly todos: HasManyRepositoryFactory<
Todo,
typeof TodoList.prototype.id
>;

constructor(
@inject('datasources.db') dataSource: juggler.DataSource,
@repository.getter(TodoRepository)
protected todoRepositoryGetter: Getter<TodoRepository>,
) {
super(TodoList, dataSource);
this.todos = this.createHasManyRepositoryFactoryFor(
'todos',
todoRepositoryGetter,
);
}
}
```

### Inclusion of Related Models

To get the related `Todo` objects for each `TodoList`, we can register the
inclusion resolver that comes with the
[`HasManyRepositoryFactory`](https://loopback.io/doc/en/lb4/apidocs.repository.hasmanyrepository.html).
We need to register this resolver to the repository class, which we can do as
follows:

{% include code-caption.html content="src/repositories/todo-list.repository.ts" %}

```ts
this.todos = this.createHasManyRepositoryFactoryFor(
'todos',
todoRepositoryGetter,
);

// Add this line to register the resolver
this.registerInclusionResolver('todos', this.todos.inclusionResolver);
```

Now when you get a `TodoList`, a `todos` property will be included that contains
your related `Todo`s, for example:

```json
{
"id": 2,
"title": "My daily chores",
"todos": [
{
"id": 3,
"title": "play space invaders",
"desc": "Become the very best!",
"todoListId": 2
}
]
}
```

On the other end, the
[`BelongsToAccessor`](https://loopback.io/doc/en/lb4/apidocs.repository.belongstoaccessor.html)
also comes with an inclusion resolver property that we can register on the
`TodoRepository`. So, let's register this resolver to the `TodoRepository`
similar to how we did it for the `TodoListRepository`:

{% include code-caption.html content="src/repositories/todo.repository.ts" %}

```ts
this.todoList = this.createBelongsToAccessorFor(
'todoList',
todoListRepositoryGetter,
);

// Add this line to register the resolver
this.registerInclusionResolver('todoList', this.todoList.inclusionResolver);
```

We're now ready to expose `TodoList` and its related `Todo` API through the
[controller](todo-list-tutorial-controller.md).

### Navigation

Previous step: [Add TodoList model](todo-list-tutorial-model.md)

Last step: [Add TodoList controller](todo-list-tutorial-controller.md)
Last step: [Add Model Relations](todo-list-tutorial-relations.md)