ORM & Sequelize 基本使用與介紹


Posted by Christy on 2022-01-14

本文為 Lidemy [BE201] 之 [ORM 與 Sequelize] 讀書筆記,內含基本介紹及如何使用。

零、基本介紹

ORM 全稱為 Object Relational Mapping,是一種把資料庫轉換成物件並且關聯對映的方法,接下來要用 Sequelize 這個框架來實作 ORM。

一、實作 Sequelize 建立一個 ORM

1. 基本設置

a. 安裝 sequelize & database $ npm install --save sequelize$ npm install --save mysql2

b. 引入並建立連線

const Sequelize = require('sequelize');

const sequelize = new Sequelize('mydb', 'username', 'password', {
  host: 'localhost',
  dialect: 'mysql'
})

c. 看範例把程式碼拿進來:Using sequelize.define,查詢文件設定 Model Definition

const User = sequelize.define('user', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
});

d. 呼叫 sequelize 幫你建立 table sequelize.sync()

Model synchronization

sequelize.sync().then(() => {
  User.create({
    firstName: 'John',
    lastName: 'Hancock'
  }).then(() => {
    console.log('created!')
  })
})

下面訊息就代表已經建立完成了,在資料庫裡面會有一個 users 的表格

Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `firstName` VARCHAR(255) NOT NULL, `lastName` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `users`
Executing (default): INSERT INTO `users` (`id`,`firstName`,`lastName`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?);
created!

2. 如何操作 sql query

Model Querying - Basics: 這裡示範了怎麼操作 CRUD

Model Querying - Finders: 常用用法,例如 findAll()findOne()

a. 找尋所有使用者:

Simple SELECT queries

sequelize.sync().then(() => {
  User.findAll().then(users => {
    console.log(users[0].id, users[0].firstName)
  })
})

設定條件,寫在 findAll() 裡面:

sequelize.sync().then(() => {
  User.findAll({
    where: {
      firstName: 'John'
    }
  }).then(users => {
    console.log(users[0].id, users[0].firstName)
  })
})

b. findOne() + update()

sequelize.sync().then(() => {
  User.findOne({
    where: {
      firstName: 'John'
    }
  }).then(user => {
    user.update({
      lastName: 'Elvis'
    })
  }).then(() => {
    console.log('done')
  })
})

c. destroy()

sequelize.sync().then(() => {
  User.findOne({
    where: {
      firstName: 'John'
    }
  }).then(user => {
    user.destroy().then(() => {
      console.log('done')
    })
  })  
})

二、建立資料庫關聯 Associations

1. 資料庫裡有兩個表格 comment & user,使用 User.hasMany(Comment) 建立關聯

下了指令後,會自動生成一個 Comments 的表格,內含 id, content, createdAt, updatedAt, userId

const User = sequelize.define('user', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
});

const Comment = sequelize.define('comment', {
  content: {
    type: Sequelize.STRING,
  }
});

User.hasMany(Comment)

2. 新增一個 UserId & content

這裡不知道為什麼無法新增,錯誤訊息是:(node:5520) UnhandledPromiseRejectionWarning: Error,先跳過,不要卡在這裡。

就在放棄的時候,我找到解答了,原來是我的 users 表格裡面,只有 id 為 2 & 3 的使用者,那當我要新增 userId 為 1 時,就會有錯誤。

const Sequelize = require('sequelize');

const sequelize = new Sequelize('mydb', 'christy', 'password', {
  host: 'localhost',
  dialect: 'mysql'
})

const User = sequelize.define('user', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
});

const Comment = sequelize.define('comment', {
  content: {
    type: Sequelize.STRING,
  }
});

User.hasMany(Comment)

sequelize.sync().then(() => {
  Comment.create({
    // 問題是我沒有 user id 為 1 的使用者,只有 2 & 3
    // 改成 userId: 2, 就好了
    userId: 1,
    content: 'hello'
  }).then(() => {
  // 執行時沒有印出 done,懷疑是語法問題,但是無解
  // 後來發現不是這個問題,問題在上面
    console.log('done')
  })
  User.findOne({
    where: {
      firstName: 'John'
    }
  }).then(user => {
  })
})

3. 尋找評論

在找「這個評論是哪一個使用者發布」時,因為 User.hasMany(Comment) 是一個單向關係,所以必須再加上Comment.belongsTo(User) 才能夠把資料撈出來。

const Sequelize = require('sequelize');

const sequelize = new Sequelize('mydb', 'christy', 'password', {
  host: 'localhost',
  dialect: 'mysql'
})

const User = sequelize.define('user', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
});

const Comment = sequelize.define('comment', {
  content: {
    type: Sequelize.STRING,
  }
});

User.hasMany(Comment)
Comment.belongsTo(User)

sequelize.sync().then(() => {
  Comment.findOne({
    where: {
      content: 'hello'
    },
    include: User
  }).then(comment => {
    console.log(JSON.stringify(comment, null, 4))
  })
})

三、Sequelize CLI 實戰 — Migrations

1. 前置作業

如果要從頭來過,記得要從 sequelize 開始安裝

a. $ npm install --save sequelize

b. $ npm install --save mysql2

c. 安裝 Migrations $ npm install --save-dev sequelize-cli

d. 初始化資料夾 $ npx sequelize-cli init

建了四個檔案: config/config.json、models、migrations、seeders

e. 改 config/config.json development 本地開發環境裡面的資料,其他兩個不用改

註:這個檔案不可以 commit 上去喔,因為裡面有帳密

f. Creating the first Model (and Migration)

$ npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string

g. Running Migrations

$ npx sequelize-cli db:migrate

註:這裡要注意,每建一個 Model 以後,就要重新跑一次 Migrations 指令(步驟 g)

h. 在 models 裡面的 user.js & comment.js 分別把 associate 寫入

static associate(models) {
  User.hasMany(models.Comment)
}

static associate(models) {
  Comment.belongsTo(models.User)
}

i. 接著再 migration 資料夾裡面新增一個 index.js 的檔案,就可以寫剛剛學的那些 methods 了

const db = require('./models')
const User = db.User
const Comment = db.Comment

User.create({
  firstName: 'hello',
  lastName: 'great'
}).then(() => {
  console.log('good')
})

j. seeders 種子資料,測網站的資料

四、實作中遇到的 error

Error log 1:

錯誤描述:跑不起來

Error: Please install tedious package manually

try 1: $ npm install tedious

Error(`Please install ${moduleName} package manually`);

try 2: $ npm install ${moduleName}

try 3: $ npm install sqlite3

用官網的 快速範例 可以跑,但是影片中的不行,後來參考官方文件,把程式碼改寫成下面這樣,就成功了。

// sequelize-test.js

const { Sequelize } = require('sequelize');

const sequelize = new Sequelize('mydb', 'christy', 'password', {
  host: 'localhost',
  dialect: 'mysql'
});

const User = sequelize.define('User', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false
  },
  lastName: {
    type: Sequelize.STRING
  }
}, {
});

(async () => {
  await sequelize.sync();
  const john = await User.create({
    firstName: 'John',
    lastName: 'Hancock',
    birthday: new Date(1980, 6, 20)
  });
  console.log(john.toJSON());
})();

註:後來發現是因為我打錯字所以連線失敗!錯字在這裡 dialect: 'mysql' 我打成 'mssql',想辦法改善。

Error log 2:

Sequel Pro 一直無法顯示資料庫,看來是需要等一下,而且有時候 XAMPP 也怪怪的,重開可能可以解決問題,目前是隔天又好了的情況這樣。

Error log 3:

使用 User.hasMany(Comment) 建立兩張表格的關聯時,Comments 裡的 userId 沒有被建立,照著影片做還是有問題,中間雖然發現大小寫問題,但最後跟著影片一模一樣做還是無解,先放著。

就在放棄的時候,我找到解答了,原來是我的 users 表格裡面,只有 id 為 2 & 3 的使用者,那當我要新增 userId 為 1 時,就會有錯誤。










Related Posts

「學習的第二層是你有沒有辦法教到別人會」-導讀外文系同學 CS50 系列課程回顧與心得

「學習的第二層是你有沒有辦法教到別人會」-導讀外文系同學 CS50 系列課程回顧與心得

Array Cardio Day 2

Array Cardio Day 2

Day 86

Day 86


Comments