什麼是 ORM? Object Relational Mapping
- 用程式裡面的物件對應到資料庫的資料,就不需要用到 SQL 指令,用 ORM 的指令就可以直接對資料庫的資料做 CRUD。
Sequelize 實際示範
更多 query 使用方法參考:sequelize 官方文件
const Sequelize = require('sequelize');
// 與資料庫連線
const sequelize = new Sequelize('ericcch24', 'ericcch24', 'zxc124040219', {
host: 'localhost',
dialect: 'mysql'
})
// Model Definition 建立資料格式
const User = sequelize.define('User', {
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING
}
}, {
});
// Model synchronization 與資料庫同步
// You can use sequelize.sync() to
// automatically synchronize all models.
sequelize.sync().then(() => {
User.findAll().then(users => {
console.log(users[0].id, users[0].firstName)
}) // 查詢資料
})
// 建立資料
sequelize.sync().then(() => {
User.create({
firstName: 'bbbbb',
lastName: 'bbbb'
}).then(() => {
console.log('created!')
})
})
資料庫關聯 Association
// 建立另一個 model,這邊是留言內容
const Comment = sequelize.define('commentsql', {
content: {
type: Sequelize.STRING,
allowNull: false
}
});
// 建立關聯
User.hasMany(Comment)
// 一個 User 可以有很多個 Comment,這邊會在 Comment 加上一欄 userId,
// ORM 會用這欄 userId 來對兩個 table 做關聯
// userId 也可以改成想要的名稱,查文件
Comment.belongsTo(User)
// 因為 hasMany 只有單向關係,所以 comment 要關聯回去 user 還要用 belongsTo
// 從 user 找到對應的 comment
sequelize.sync().then(() => {
Comment.create({
// 在 comment 新增內容,可以對應到 User 的 ID
UserId: 3,
content: 'yyyoyoo'
}).then(() => {
console.log('done')
})
User.findOne({
where: {
firstName: 'John'
},
include: Comment
// 把 user 底下加上 comment include,
// 就可以拿對應到的資料
}).then(user => {
console.log(JSON.stringify(user.commentsqls, null, 4))
// 可以拿到該 user 所對應到的 commentsql 的資料
})
})
// 從 comment 找到對應的 user
sequelize.sync().then(() => {
Comment.findOne({
where: {
content: 'hello'
},
include: User
//把 comment 底下加上 user include,
//就可以拿對應到的資料
}).then(comment => {
console.log(JSON.stringify(comment.User.firstName, null, 4))
// 可以從 comment 拿到對應的 user
})
})
Sequelize CLI
- 方便管理用,讓程式碼更有結構
config.json
: 資料庫的連線設定model:generate
來建立 model 與 migration 檔案(以下指令擇一使用):- 指令 1:
npx sequelize-cli model:generate --name User --attributes firstName:string,lastName:string,email:string
- 指令 2:
./node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string
User 是 model 名稱,習慣用大寫,會在 model 資料夾建立 user.js 檔案。
- 指令 1:
- migration 資料夾會有負責紀錄資料庫的改動紀錄的檔案,執行
npx sequelize-cli db:migrate
指令後才會真正建立資料庫。 - 在剛剛建立的 models 的檔案建立關聯
5.最後就可以從外部的 index.js 來引入 model,可以直接操作資料庫'use strict'; const { Model } = require('sequelize'); module.exports = (sequelize, DataTypes) => { class User extends Model { /** * Helper method for defining associations. * This method is not a part of Sequelize lifecycle. * The `models/index` file will call this method automatically. */ static associate(models) { User.hasMany(models.Comment) // 這邊寫關聯的部分 } }; User.init({ firstName: DataTypes.STRING, lastName: DataTypes.STRING, email: DataTypes.STRING }, { sequelize, modelName: 'User', }); return User; };
```javascript=
const db = require('./models')
const User = db.User
const Comment = db.Comment
User.create({
firstName: 'poop',
lastName: 'Stan'
}).then(() => {
console.log('good')
})
* 所以不需要用前面的 sync() 來控制資料庫,可以用 migration。
---
## W17 檢討範例 async await
[還有其他部分參考:第十七週檢討範例](https://github.com/Lidemy/mentor-program-4th/tree/master/examples/week17)
在用 Promise 的時候你通常都是在一個 function 裡面,所以這樣寫是沒有用的:
```javascript=
function handle(req, res) {
User.findBy({
id: 1
}).then(user => {
if(!user) {
res.redirect('/')
return
}
}).then(user => {
// 這邊還是會執行到
User.create()
})
}
因為 promise chaining 的特性,所以最後的那個 .then 還是會執行到,你寫的 return 是你傳進去 then
的那個 function 的 return,不是 handle
的 return。
這邊建議大家改用 async await,程式碼簡單好懂:
async function handle(req, res) {
const user = await User.findBy({
id: 1
})
if(!user) {
res.redirect('/')
return
}
User.create()
}