如果不想在nodejs中大量的手寫sql,就可以採用orm框架sequelize,它非常類似於Java的JPA,讓你的代碼看起來更規範簡潔高效。不過在採用sequelize編寫的過程中遇到了一些問題,而網上的資料又太少;不是沒有去sequelize官網看過,主要是官網的API示例都是針對一般的js語法,而我的項目使用了TypeScript,有好多地方功能雖然可以正常執行,但是代碼下面會冒紅(紅顏色波浪線),鼠標放上去提示:TS2322:the type xxx is not assign to xxxxx。這種屬於語法問題,typescript要求的比較嚴格。
下面來看一個例子,API爲findOrCreate,意思是根據條件查找,如果找到就返回,沒找到則創建一條。在對實體類進行jpa操作時,首先用sequelize定義字段類型與數據庫字段的映射,例如:
export const StudentModel = sequelize.define('student', {
id: {
type: Sequelize.BIGINT,
field: 'id',
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING,
field: 'name'
},
age: {
type: Sequelize.TINYINT,
field: 'age'
},
tel: {
type: Sequelize.STRING,
field: 'tel'
},
createTime: {
type: Sequelize.BIGINT,
field: 'create_time'
},
updateTime: {
type: Sequelize.BIGINT,
field: 'update_time'
}
}, {
timestamps: false,
tableName: 'student'
});
按照官網 findOrCreate的用法,根據where條件後面的選項來查找記錄,如果沒找到,則將where裏面的條件和defaults裏面的屬性一起作爲待插入項,所以我只需要像如下這麼寫:
await StudentModel.findOrCreate(
{
where: {name: `${name}`, tel: `${tel}`},
defaults: {
age: `${age}`,
createTime: `${time}`,
updateTime: `${time}`}
});
事實是運行功能執行正常,但是由於採用了TypeScript來編寫,“defaults”那裏此時會冒紅,而且持續集成的編譯不會通過,鼠標放在defaults上會提示TS2322: type 'xxxx' is not assignable to type 'xxxx'。意思是類型對應不上,要求你defaults裏面的參數必須和StudentModel裏面定義的完全一致,少一個都不行,我不知道爲什麼會這樣,難道sequelize沒有對typescript做優化嗎?defaults裏面如果把所有參數都填上,怪怪的,我id是自增的,肯定不能給id默認值,所以賦給null,where條件裏面已經填了兩個參數還要再填一遍,沒辦法先編譯通過再說,改正後如下:
await StudentModel.findOrCreate(
{
where: {name: `${name}`, tel: `${tel}`},
defaults: {id:null,
name: `${name}`,
tel: `${tel}`,
age: `${age}`,
createTime: `${time}`,
updateTime: `${time}`}
});
再來說第二個問題:sequelize的api有一個回調方法,有的是then,有的是spread,這裏根據官網文檔使用spread將結果切分爲倆個部分,一個是返回的實例對象,一個是行爲布爾值,我是這麼理解的。
await StudentModel.findOrCreate(
{
where: {name: `${name}`, tel: `${tel}`},
defaults: {id:null,
name: `${name}`,
tel: `${tel}`,
age: 21,
createTime: `${time}`,
updateTime: `${time}`}
})
.spread((student, created) => {
// 如果找到則直接更新,沒找到會自動創建
if (created === false) {
(async () => {
await StudentModel.update(
{age: 22, updateTime: `${time}`},
{where: {id: student.id}});
})();
}
});
此處不管是找到也好,創建的也好,spread第一個參數返回的都是student對象,然後緊接着我會用到student對象的屬性id值,本地執行也是正常的,但就是在student.id那裏冒紅 ,也是報TS2322啥的,意思是說student是object類型的無法點出id屬性。後來問了web前端工程師,他說要對spread的第一個參數student加個類型,要加類型就要先定義類型,這樣寫:
interface Student {
id:number;
name?:string;
...
...
}
定義好以後 ,對spread的第一個參數student加個類型,如下所示
.spread((student: Student, created) => {
當然了,如果你嫌麻煩,也可以直接將其定義爲any類型,對象依然是原來的那個對象,只是讓typescript不再報語法錯誤
.spread((student: any, created) => {
這次student.id不再冒紅了。我說我已經定義了一個StudentModel,這裏的類型換成StudentModel怎麼也冒紅,他說typescript裏面有專門定義自己屬性的接口,不能混淆。
其實sequelize還有一個叫upsert的API,是updateOrInsert的簡稱,where條件裏面必須包含能定爲一條記錄的唯一索引,否則無效,就拿上面的例子來說,如果你能獲取到id值,則上面的寫法可以換成upsert一個api就夠了,很精簡。
最後如果使用了sequelize後,啓動時控制檯報這個錯
sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at
此時可以這麼做,修改你的sequelize.ts文件,重點在於operatorsAliases這一大堆:
const Op = Sequelize.Op;
export const sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.password, {
host: dbConfig.host,
port: dbConfig.port,
dialect: 'mysql',
operatorsAliases: {
$eq: Op.eq,
$ne: Op.ne,
$gte: Op.gte,
$gt: Op.gt,
$lte: Op.lte,
$lt: Op.lt,
$not: Op.not,
$in: Op.in,
$notIn: Op.notIn,
$is: Op.is,
$like: Op.like,
$notLike: Op.notLike,
$iLike: Op.iLike,
$notILike: Op.notILike,
$regexp: Op.regexp,
$notRegexp: Op.notRegexp,
$iRegexp: Op.iRegexp,
$notIRegexp: Op.notIRegexp,
$between: Op.between,
$notBetween: Op.notBetween,
$overlap: Op.overlap,
$contains: Op.contains,
$contained: Op.contained,
$adjacent: Op.adjacent,
$strictLeft: Op.strictLeft,
$strictRight: Op.strictRight,
$noExtendRight: Op.noExtendRight,
$noExtendLeft: Op.noExtendLeft,
$and: Op.and,
$or: Op.or,
$any: Op.any,
$all: Op.all,
$values: Op.values,
$col: Op.col
},
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
});
參考https://stackoverflow.com/questions/46608382/sequelize-deprecated-error-message