본문 바로가기
카테고리 없음

Sequelize.js Association hasOne 정리

by Hide­ 2018. 7. 16.
반응형

두번째 내용인 hasOne() 관계에 대한 포스팅이다.

이전 글과 마찬가지로 http://docs.sequelizejs.com/manual/tutorial/associations.html 이 글에서 

hasOne() 부분만 따로 가져와서 번역했다.


HasOne

hasOne은 1:1관계에 대한 외래키가 target 모델에 있을 때 사용한다.

const User = sequelize.define('user', {/* ... */})
const Project = sequelize.define('project', {/* ... */})

// One-way associations
Project.hasOne(User)

/*
  이번 예제에서 hasOne은 User모델에  projectId 컬럼을 추가할 것이다.
  게다가 Project.prototype은 define을 통해 들어오는 첫번째 인자에 따라 getUser와 setUser라는 메소드를 얻게 된다.
  만약 underscore 옵션을 줬다면 projectId 대신 project_id라는 컬럼이 생성된다.

  외래키는 users 테이블에 생성된다.

  또한 외래키를 직접 지정할 수 있다.
*/

Project.hasOne(User, { foreignKey: 'initiator_id' })

/*
  Sequelize는 define()의 첫번째 파라미터를 유저 모델에 있는 accessor 메소드의 이름으로 사용하기 때문에 hasOne()에 특별한 옵션을 줄수도 있다.
*/

Project.hasOne(User, { as: 'Initiator' })
// 이제 Project.getInitiator와 Project.setInitiator 메소드를 사용할 수 있다.

// 또는 특정한 자체 참조를 사용할수도 있다.
const Person = sequelize.define('person', { /* ... */})

// 이번에는 자기 참조에 관한 예제를 만들어보자. Person.hasOne(Person, {as: 'Father'}) // 위 라인은 FatherId 컬럼을 Person 모델에 추가한다. // 또한 아래처럼 사용할수도 있다: Person.hasOne(Person, {as: 'Father', foreignKey: 'DadId'}) // 위 라인은 DadId 컬럼을 Person 모델에 추가한다. // 아래 두개의 메소드를 사용할 수 있다: Person.setFather Person.getFather // 만약 두번의 join을 사용하고 싶다면, 같은 테이블을 사용하면 된다. Team.hasOne(Game, {as: 'HomeTeam', foreignKey : 'homeTeamId'}); Team.hasOne(Game, {as: 'AwayTeam', foreignKey : 'awayTeamId'}); Game.belongsTo(Team);

대부분의 경우 BelongsTo는 source로 지정된 target모델에 자동으로 외래키를 생성하기 때문에 1:1관계에서는 BelongsTo를 설정해주는 것이 좋다.


HasOne과 BelongsTo의 차이점

Sequelize에서 1:1관계는 HasOne과 BelongsTo로 설정해줄 수 있다. 두가지 모두 각각이 적합한 상황이 있다.

이번 예제를 통해 둘의 차이점에 대해서 살펴본다.


Player와 Team이라는 두개의 테이블이 있다고 가정해보자.

const Player = this.sequelize.define('player', {/* attributes */})
const Team  = this.sequelize.define('team', {/* attributes */});

Sequelize에서 두개의 모델을 연결해주려면 source와 target을 사용하면 된다.

아래를 보면 Player는 source이고 Team은 target이다.

Player.belongsTo(Team);
//Or
Player.hasOne(Team);

아래는 Team을 source로 삼고 Player를 target으로 삼는다.

Team.belongsTo(Player);
//Or
Team.hasOne(Player);

HasOne과 BelongsTo는 관계키를 각각 다른 모델에 생성한다.

HasOne은 관계키를 target모델에 생성하는 반면 BelongsTo는 source모델에 생성한다.

아래 예제를 통해 BelongsTo와 HasOne의 동작에 대해 살펴본다. 

const Player = this.sequelize.define('player', {/* attributes */})
const Coach  = this.sequelize.define('coach', {/* attributes */})
const Team  = this.sequelize.define('team', {/* attributes */});

Player 모델이 팀에 대한 정보를 가지고 있는 teamId 컬럼을 가지고 있다고 가정해보자.

각 팀의 코치에 대한 정보는 Team 모델의 coachId 컬럼으로 존재한다.

각각 다른 모델에 외래키 관계가 존재하기 때문에 이 두개의 시나리오는 다른 종류의 1:1 관계가 필요하다.


만약 관계에 대한 정보가 source 모델에 존재한다면 우리는 belongsTo를 사용할 수 있다.

아래의 경우, Player는 teamId 컬럼을 가지고 있기 때문에 belongsTo가 적합하다.

Player.belongsTo(Team)  // `teamId` 는 Player(source 모델)에 생성된다.

하지만 관계에 대한 정보가 target 모델에 존재한다면 hasOne을 사용해야 한다.

아래의 경우, Team 모델이 Coach에 대한 정보를 coachId라는 컬럼으로 가지고 있기 때문에 hasOne이 적합하다.

Coach.hasOne(Team)  // `coachId` 는 Team(target 모델)에 생성된다.