Skip to content

One to one relationship

Ravi Teja Gudapati edited this page Feb 19, 2019 · 8 revisions

One to one relationship maps one record in a table to another record in a referred table.

In Jaguar, one-to-one mapping is performed using HasOne and BelongsTo annotations. Let us take an user-address example. Each user has an address.

How to

Parent model

The linked field in the parent model is annotated with HasOne annotation. In this case, User model is linked to Address model using the address field. HasOne takes the bean of the referred table as the argument. In this case, AddressBean.

HasOne basically says: "Model User has a one-to-one relationship with model Address by field address".

class User {
  @PrimaryKey(length: 50)
  String id;

  @Column(length: 50)
  String name;

  @HasOne(AddressBean)
  Address address;

  User({this.id, this.name, this.address});
}

Referred table

The foreign key in the referred table should be annotated by BelongsTo annotation. In this case, userId is the foreign key that is used to link a user to the address by user's id. BelongsTo annotation takes the bean of the parent table as the argument. In this case, UserBean.

BelongsTo basically says: "Model Address belongs to model User referred by userId field".

class Address {
  @PrimaryKey(length: 50)
  String id;

  @Column(length: 150)
  String street;

  @BelongsTo(UserBean)
  String userId;

  Address({this.id, this.street, this.userId});
}

Use refCol argument in BelongsTo to specify the matching foreign key column in the parent table. It defaults to id.

Beans

Templates for UserBean and AddressBean should be written with members AddressBean addressBean and UserBean userBean respectively. The generated bean logic will use these fields to perform operation on the linked tables.

@GenBean()
class UserBean extends Bean<User> with _UserBean {
  UserBean(Adapter adapter)
      : addressBean = AddressBean(adapter),
        super(adapter);

  final AddressBean addressBean;

  String get tableName => 'oto_simple_user';
}

@GenBean()
class AddressBean extends Bean<Address> with _AddressBean {
  UserBean _userBean;
  UserBean get userBean => _userBean ??= UserBean(adapter);

  AddressBean(Adapter adapter) : super(adapter);

  String get tableName => 'oto_simple_address';
}

Usage

Besides usual CRUD operations, for models with one-to-one relations, Jaguar generates following logic:

  1. Cascaded inserts and upserts
  2. Cascaded deletes
  3. Cascaded updates
  4. Auto preload child field
  5. Manual preload child field
  6. Find parent by child instance

Cascaded inserts and upserts

insert method of parent bean has cascade named argument. When this argument is set to true, the child model is automatically inserted into the child table with foreign key filled in.

    final user = User()
      ..id = '1'
      ..name = 'Teja'
      ..address = (Address()
        ..id = '1'
        ..street = 'Stockholm');
    await userBean.insert(user, cascade: true);

Cascaded deletes

remove method of parent bean has cascade named argument. When this argument is set to true, the linked child model is automatically removed from the child table by the foreign key.

await userBean.remove('1', cascade: true);

Cascaded updates

update method of parent bean has cascade named argument. When this argument is set to true, the linked child model is automatically updated.

    User user = await userBean.find('1', preload: true);
    user.name = 'Teja Hackborn';
    user.address.street = 'Stockholm, Sweden';
    await userBean.update(user, cascade: true);

Auto preload child field

find method of parent bean has preload named argument. When this argument is set to true, the child record is automatically fetched and filled into the parent model when a parent record is queried.

final user = await userBean.find('1', preload: true);

Manual preload child field

TODO

Find parent by child instance

The child model can be queried by parent's primary key using the generated findBy'ParentModel' (in this case, findByUser).

final address = await addressBean.findByUser(user.id);

The preload argument to findByUser automatically preloads the child field in parent model.