해당 자료는 seqeulize 5의 공식문서를 번역한 자료입니다.
Model instances는 DAO(Data Access Object)이다.
이번 가이드는 아래와 같은 setup을 가정으로 진행된다.
const { Sequelize, Model, DataTypes } = require("sequelize");
const sequelize = new Sequelize("sqlite::memory:");
const User = sequelize.define("user", {
name: DataTypes.TEXT,
favoriteColor: {
type: DataTypes.TEXT,
defaultValue: 'green'
},
age: DataTypes.INTEGER,
cash: DataTypes.INTEGER
});
(async () => {
await sequelize.sync({ force: true });
// Code here
})();
Model은 클래스임에도 new
키워드를 통해서 직접 인스턴스를 만들지 않는다. 대신 build
메소드를 사용한다.
const jane = User.build({ name: "Jane" });
console.log(jane instanceof User); // true
console.log(jane.name); // "Jane"
위 코드는 데이터베이스와 커뮤니케이션하지 않는다.(심지어 asynchronus조차 없다) build
메소드는 데이터베이스의 매핑된 데이터 오브젝트를 생성하는 역할만한다. 데이터베이스에 저장하기 위해서는 save
메소드를 사용한다.
await jane.save();
console.log('Jane was saved to the database!');
save
메소드 앞에 await
키워드가 있는 것에 주목하자. 즉 save
는 asynchronus(비동기) 메소드이다. 사실 Seqeulize의 대부분 method는 비동기이나 build
는 예외 중 하나이다.
Seqeulize는 build
와 save
메소드를 결합한 create
메소드를 제공한다.
const jane = await User.create({ name: "Jane" });
// Jane exists in the database now!
console.log(jane instanceof User); // true
console.log(jane.name); // "Jane"
model instance를 logging하기 위해 바로 console.log를 사용하는 것은 Seqeulize instance가 가지는 많은 정보들을 출력한다. 대신에 .toJSON()
메소드를 이용해서 출력하는 것을 권장한다.
.toJSON()
메소드는 자동적으로 인스턴스에 JSON.stringify
를 적용시켜준다.
const jane = await User.create({ name: "Jane" });
// console.log(jane); // Don't do this
console.log(jane.toJSON()); // This is good!
console.log(JSON.stringify(jane, null, 4)); // This is also good!
Default values
Build를 통해 생성한 인스턴스는 자동적으로 default values를 가진다.
const jane = User.build({ name: "Jane" });
console.log(jane.favoriteColor); // "green"
save
함수를 다시 호출함으로서 인스턴스를 변경 할 수 있다.
const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
jane.name = "Ada";
// the name is still "Jane" in the database
await jane.save();
// Now the name was updated to "Ada" in the database!
destory
호출을 통해 인스턴스를 삭제 할 수 있다.
const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
await jane.destroy();
// Now this entry was removed from the database
reload
함수를 통해 데이터베이스로부터 인스턴스를 재로드 할 수 있다.
const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
jane.name = "Ada";
// the name is still "Jane" in the database
await jane.reload();
console.log(jane.name); // "Jane"
reload
함수는 데이터베이스의 최근 데이터를 가져오기 위한 SELECT
쿼리를 생성한다.
save
를 호출 할 때 column names array를 넘겨줌으로서 저장할 attributes 정의가 가능하다.
이것은 이전의 정의된 오브젝트의 속성을 설정 할 때 유용하다. 예를 들어 웹앱 형태를 통해 오브젝트의 value를 가져올 때이다. 게다가 이것은 내부적으로 update
구현체를 사용한다.
const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
console.log(jane.favoriteColor); // "green"
jane.name = "Jane II";
jane.favoriteColor = "blue";
await jane.save({ fields: ['name'] });
console.log(jane.name); // "Jane II"
console.log(jane.favoriteColor); // "blue"
// The above printed blue because the local object has it set to blue, but
// in the database it is still "green":
await jane.reload();
console.log(jane.name); // "Jane II"
console.log(jane.favoriteColor); // "green"
save
메소드는 실제로 변한 필드에 대해서만 update가 일어나도록 내부적으로 최적화되어 있다. 아무것도 바꾸지 않은 상태에서 save
를 호출하면, Sequelize는 save가 필요하지 않음을 알고 아무 동작도 하지 않는다. 즉 쿼리가 만들어지지 않는다. (단 여전히 Promise가 리턴되지만 곧바로 resolve 된다.)
또한 성능 향샹을 위해 save
를 호출 할 때 변한 몇 개의 필드에 대해서만 UPDATE
쿼리가 보내진다.
JPA의 save는 전체 필드 대상이다. 특정 필드만 update 하기위해서는 DynamicUpdate 어노테이션을 별도로 사용해야한다.
concurrency 이슈 없이 인스턴스 value의 증감을 위해서 Seqeulize는 increment
와 decrement
메소드를 제공한다.
const jane = await User.create({ name: "Jane", age: 100 });
const incrementResult = await user.increment('age', { by: 2 });
// Note: to increment by 1 you can omit the `by` option and just do `user.increment('age')`
// In PostgreSQL, `incrementResult` will be the updated user, unless the option
// `{ returning: false }` was set (and then it will be undefined).
// In other dialects, `incrementResult` will be undefined. If you need the updated instance, you will have to call `user.reload()`.
increment
, decrement
는 다수의 필드에 대한 지원도 가능하다
const jane = await User.create({ name: "Jane", age: 100, cash: 5000 });
await jane.increment({
'age': 2,
'cash': 100
});
// If the values are incremented by the same amount, you can use this other syntax as well:
await jane.increment(['age', 'cash'], { by: 2 });