TypeORM æ¯ä¸ä¸ªORMæ¡æ¶ï¼å®å¯ä»¥è¿è¡å¨ NodeJSãBrowserãCordovaãPhoneGapãIonicãReact NativeãExpo å Electron å¹³å°ä¸ï¼å¯ä»¥ä¸ TypeScript å JavaScript (ES5,ES6,ES7,ES8)ä¸èµ·ä½¿ç¨ã å®çç®æ æ¯å§ç»æ¯æææ°ç JavaScript ç¹æ§å¹¶æä¾é¢å¤çç¹æ§ä»¥å¸®å©ä½ å¼åä»»ä½ä½¿ç¨æ°æ®åºçï¼ä¸ç®¡æ¯åªæå å¼ è¡¨çå°ååºç¨è¿æ¯æ¥æå¤æ°æ®åºç大åä¼ä¸åºç¨ï¼åºç¨ç¨åºã
ä¸åäºç°æçææå ¶ä» JavaScript ORM æ¡æ¶ï¼TypeORM æ¯æ Active Record å Data Mapper 模å¼ï¼è¿æå³çä½ å¯ä»¥ä»¥æé«æçæ¹å¼ç¼åé«è´¨éçãæ¾è¦åçã坿©å±çãå¯ç»´æ¤çåºç¨ç¨åºã
TypeORM åèäºå¾å¤å ¶ä»ä¼ç§ ORM çå®ç°, æ¯å¦ Hibernate, Doctrine å Entity Frameworkã
TypeORM çä¸äºç¹æ§:
- æ¯æ DataMapper å ActiveRecord (éä½ éæ©)
- å®ä½åå
- æ°æ®åºç¹æ§åç±»å
- å®ä½ç®¡ç
- åå¨åºåèªå®ä¹åå¨åº
- æ¸ æ°çå¯¹è±¡å ³ç³»æ¨¡å
- å ³èï¼å ³ç³»ï¼
- 贪婪åå»¶è¿å ³ç³»
- ååçï¼ååçåèªå¼ç¨çå ³ç³»
- æ¯æå¤éç»§æ¿æ¨¡å¼
- 级è
- ç´¢å¼
- äºå¡
- è¿ç§»åèªå¨è¿ç§»
- è¿æ¥æ±
- 主ä»å¤å¶
- 使ç¨å¤ä¸ªæ°æ®åºè¿æ¥
- 使ç¨å¤ä¸ªæ°æ®åºç±»å
- è·¨æ°æ®åºåè·¨æ¨¡å¼æ¥è¯¢
- ä¼é çè¯æ³ï¼çµæ´»è强大ç QueryBuilder
- å·¦èæ¥åå èæ¥
- 使ç¨èæ¥æ¥è¯¢çéå½å页
- æ¥è¯¢ç¼å
- åå§ç»ææµ
- æ¥å¿
- çå¬è å订é è ï¼é©åï¼
- æ¯æéå 表模å¼
- 卿¨¡åæè å离çé ç½®æä»¶ä¸å£°ææ¨¡å¼
- json / xml / yml / env æ ¼å¼çè¿æ¥é ç½®
- æ¯æ MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / sql.js
- æ¯æ MongoDB NoSQL æ°æ®åº
- å¯å¨ NodeJS / æµè§å¨ / Ionic / Cordova / React Native / Expo / Electron å¹³å°ä¸ä½¿ç¨
- æ¯æ TypeScript å JavaScript
- çæé«æ§è½ãçµæ´»ãæ¸ æ°åå¯ç»´æ¤ç代ç
- éµå¾ªææå¯è½çæä½³å®è·µ
- å½ä»¤è¡å·¥å ·
è¿ææ´å¤...
éè¿ä½¿ç¨ TypeORM ä½ ç models çèµ·æ¥åè¿æ ·:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
age: number;
}
é»è¾æä½å°±åæ¯è¿æ ·:
const user = new User();
user.firstName = "Timber";
user.lastName = "Saw";
user.age = 25;
await repository.save(user);
const allUsers = await repository.find();
const firstUser = await repository.findOne(1); // find by id
const timber = await repository.findOne({ firstName: "Timber", lastName: "Saw" });
await repository.remove(timber);
æè
ï¼å¦æä½ æ´å欢使ç¨ActiveRecordå®ç°ï¼ä¹å¯ä»¥è¿æ ·ç¨ï¼
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from "typeorm";
@Entity()
export class User extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
age: number;
}
é»è¾æä½å¦ä¸æç¤º:
const user = new User();
user.firstName = "Timber";
user.lastName = "Saw";
user.age = 25;
await user.save();
const allUsers = await User.find();
const firstUser = await User.findOne(1);
const timber = await User.findOne({ firstName: "Timber", lastName: "Saw" });
await timber.remove();
å ¥é¨
å®è£ â
éè¿
npmå®è£ :npm install typeorm --saveä½ è¿éè¦å®è£
reflect-metadata:npm install reflect-metadata --saveå¹¶ä¸éè¦å¨åºç¨ç¨åºçå ¨å±ä½ç½®å¯¼å ¥ï¼ä¾å¦å¨
app.tsä¸ï¼import "reflect-metadata";ä½ å¯è½è¿éè¦å®è£ node typings(ä»¥æ¤æ¥ä½¿ç¨ Node çæºè½æç¤º):
npm install @types/node --saveå®è£ æ°æ®åºé©±å¨:
MySQL æè MariaDB
npm install mysql --save(ä¹å¯ä»¥å®è£mysql2)PostgreSQL
npm install pg --saveSQLite
npm install sqlite3 --saveMicrosoft SQL Server
npm install mssql --savesql.js
npm install sql.js --saveOracle
npm install oracledb --saveæ ¹æ®ä½ 使ç¨çæ°æ®åºï¼ä» å®è£ å ¶ä¸ä¸ä¸ªå³å¯ã è¦ä½¿ Oracle 驱å¨ç¨åºæ£å¸¸å·¥ä½ï¼éè¦æç §å ¶ç«ç¹ä¸çå®è£ 说æè¿è¡æä½ã
MongoDB (è¯éªæ§)
npm install mongodb --saveNativeScript, react-native å Cordova
æ¥ç æ¯æçå¹³å°
TypeScript é ç½®â
æ¤å¤ï¼è¯·ç¡®ä¿ä½ 使ç¨çæ¯ TypeScript ç¼è¯å¨çæ¬2.3ææ´é«çæ¬ï¼å¹¶ä¸å·²ç»å¨tsconfig.jsonä¸å¯ç¨äºä»¥ä¸è®¾ç½®:
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
ä½ å¯è½è¿éè¦å¨ç¼è¯å¨é项çlibä¸å¯ç¨es6ï¼æè
ä»@typeså®è£
es6-shimã
å¿«éå¼å§â
å¼å§ä½¿ç¨ TypeORM çæå¿«æ¹æ³æ¯ä½¿ç¨å ¶ CLI å½ä»¤çæå¯å¨é¡¹ç®ã åªæå¨ NodeJS åºç¨ç¨åºä¸ä½¿ç¨ TypeORM æ¶ï¼æ¤æä½æææãå¦æä½ ä½¿ç¨çæ¯å ¶ä»å¹³å°ï¼è¯·ç»§ç»æ§è¡åæ¥æåã
é¦å å ¨å±å®è£ TypeORM:
npm install typeorm -g
ç¶å转å°è¦å建æ°é¡¹ç®çç®å½å¹¶è¿è¡å½ä»¤ï¼
typeorm init --name MyProject --database mysql
å
¶ä¸nameæ¯é¡¹ç®çåç§°ï¼databaseæ¯æ¨å°ä½¿ç¨çæ°æ®åºã
æ°æ®åºå¯ä»¥æ¯ä»¥ä¸å¼ä¹ä¸: mysql, mariadb, postgres, sqlite, mssql, oracle, mongodb,
cordova, react-native, expo, nativescript.
æ¤å½ä»¤å°å¨MyProjectç®å½ä¸çæä¸ä¸ªå
å«ä»¥ä¸æä»¶çæ°é¡¹ç®:
MyProject
âââ src // TypeScript 代ç
â âââ entity // åå¨å®ä½ï¼æ°æ®åºæ¨¡åï¼çä½ç½®
â â âââ User.ts // ç¤ºä¾ entity
â âââ migration // åå¨è¿ç§»çç®å½
â âââ index.ts // ç¨åºæ§è¡ä¸»æä»¶
âââ .gitignore // gitignoreæä»¶
âââ ormconfig.json // ORMåæ°æ®åºè¿æ¥é
ç½®
âââ package.json // node module ä¾èµ
âââ README.md // ç®åç readme æä»¶
âââ tsconfig.json // TypeScript ç¼è¯é项
ä½ è¿å¯ä»¥å¨ç°æ node 项ç®ä¸è¿è¡
typeorm initï¼ä½è¦æ³¨æï¼æ¤æä½å¯è½ä¼è¦çå·²æçæäºæä»¶ã
æ¥ä¸æ¥å®è£ 项ç®ä¾èµé¡¹ï¼
cd MyProject
npm install
å¨å®è£
è¿ç¨ä¸ï¼ç¼è¾ormconfig.jsonæä»¶å¹¶å¨å
¶ä¸æ¾ç½®æ¨èªå·±çæ°æ®åºè¿æ¥é
ç½®é项ï¼
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "test",
"password": "test",
"database": "test",
"synchronize": true,
"logging": false,
"entities": ["src/entity/**/*.ts"],
"migrations": ["src/migration/**/*.ts"],
"subscribers": ["src/subscriber/**/*.ts"]
}
ç»å¤§å¤æ°æ
åµä¸ï¼ä½ åªéè¦é
ç½®
host, username, password, database æè
portã
宿é 置并å®è£ ææ node modules åï¼å³å¯è¿è¡åºç¨ç¨åºï¼
npm start
è³æ¤ä½ çåºç¨ç¨åºåºè¯¥æåè¿è¡å¹¶å°æ°ç¨æ·æå ¥æ°æ®åºãä½ å¯ä»¥ç»§ç»ä½¿ç¨æ¤é¡¹ç®å¹¶éææéçå ¶ä»æ¨¡åå¹¶å建æ´å¤å®ä½ã
ä½ å¯ä»¥éè¿è¿è¡
typeorm init --name MyProject --database mysql --expressæ¥çæä¸ä¸ªæ´é«çº§ç Express 项ç®
忥æåâ
æ¨å¯¹ ORM æä½æå¾ ï¼æ¨ææå®å°ä¸ºæ¨åå»ºæ°æ®åºè¡¨ï¼å¹¶ä¸æ éç¼å大éé¾ä»¥ç»´æ¤ç SQL è¯å¥æ¥æ¥æ¾/æå ¥/æ´æ°/å 餿¨çæ°æ®ãæ¬æåå°åæ¨å±ç¤ºå¦ä½ä»å¤´å¼å§è®¾ç½® TypeORM å¹¶å®ç°è¿äºæä½ã
å建ä¸ä¸ªæ¨¡åâ
ä½¿ç¨æ°æ®åºä»å建表å¼å§ãå¦ä½åè¯ TypeORM åå»ºæ°æ®åºè¡¨ï¼çæ¡æ¯ - éè¿æ¨¡åã åºç¨ç¨åºä¸ç模å峿¯æ°æ®åºä¸ç表ã
举个ä¾å, ä½ æä¸ä¸ªPhoto 模å:
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
}
å¹¶ä¸å¸æå° photos åå¨å¨æ°æ®åºä¸ãè¦å¨æ°æ®åºä¸åå¨å 容ï¼é¦å éè¦ä¸ä¸ªæ°æ®åºè¡¨ï¼å¹¶ä»æ¨¡åä¸åå»ºæ°æ®åºè¡¨ã使¯å¹¶éæææ¨¡åï¼åªææ¨å®ä¹ä¸ºentitiesçæ¨¡åã
å建ä¸ä¸ªå®ä½â
Entityæ¯ç±@Entityè£
饰å¨è£
é¥°çæ¨¡åãå°ä¸ºæ¤ç±»æ¨¡ååå»ºæ°æ®åºè¡¨ãä½ å¯ä»¥ä½¿ç¨ TypeORM å¤çåå¤çå®ä½ï¼å¯ä»¥ä½¿ç¨å®ä»¬ load/insert/update/remove å¹¶æ§è¡å
¶ä»æä½ã
让æä»¬å°Photo模åä½ä¸ºä¸ä¸ªå®ä½
import { Entity } from "typeorm";
@Entity()
export class Photo {
id: number;
name: string;
description: string;
filename: string;
views: number;
isPublished: boolean;
}
ç°å¨ï¼å°ä¸ºPhotoå®ä½å建ä¸ä¸ªæ°æ®åºè¡¨ï¼æä»¬å°è½å¤å¨åºç¨ç¨åºä¸çä»»ä½ä½ç½®ä½¿ç¨å®ã
æä»¬å·²ç»å建äºä¸ä¸ªæ°æ®åºè¡¨ï¼ä½æ¯æ²¡æåªä¸ªå段å±äºåªä¸åï¼ä¸é¢è®©æä»¬å¨æ°æ®åºè¡¨ä¸å建å åã
æ·»å 表åâ
è¦æ·»å æ°æ®åºåï¼ä½ åªéè¦å°è¦çæçå®ä½å±æ§å ä¸@Columnè£
饰å¨ã
import { Entity, Column } from "typeorm";
@Entity()
export class Photo {
@Column()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
ç°å¨ id, name, description, filename, views å isPublished åå°ä¼è¢«æ·»å å°photo表ä¸ã
æ°æ®åºä¸çåç±»åæ¯æ ¹æ®ä½ 使ç¨ç屿§ç±»åæ¨æçï¼ä¾å¦ï¼ numberå°è¢«è½¬æ¢ä¸ºintegerï¼stringå°è½¬æ¢ä¸ºvarcharï¼boolean转æ¢ä¸ºboolçãä½ä½ ä¹å¯ä»¥éè¿å¨@Columnè£
饰å¨ä¸é弿å®åç±»åæ¥ä½¿ç¨æ°æ®åºæ¯æçä»»ä½åç±»åã
æä»¬å·²ç»çæäºä¸ä¸ªå å«åçæ°æ®åºè¡¨ï¼ä½è¿å©ä¸ä¸ä»¶äºãæ¯ä¸ªæ°æ®åºè¡¨å¿ é¡»å ·æå å«ä¸»é®çåã
å建主åâ
æ¯ä¸ªå®ä½å¿
é¡»è³å°æä¸ä¸ªä¸»é®åãè¿æ¯å¿
é¡»çï¼ä½ æ æ³é¿å
ãè¦ä½¿åæä¸ºä¸»é®ï¼æ¨éè¦ä½¿ç¨@PrimaryColumnè£
饰å¨ã
import { Entity, Column, PrimaryColumn } from "typeorm";
@Entity()
export class Photo {
@PrimaryColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
å建èªå¨çæçåâ
åè®¾ä½ å¸æ id åèªå¨çæï¼è¿ç§°ä¸º auto-increment/sequence/serial/generated identity columnï¼ã为æ¤ä½ éè¦å°@PrimaryColumnè£
饰卿´æ¹ä¸º@PrimaryGeneratedColumnè£
饰å¨ï¼
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
filename: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
åæ°æ®ç±»åâ
æ¥ä¸æ¥ï¼è®©æä»¬ä¿®å¤æ°æ®ç±»åãé»è®¤æ åµä¸ï¼å符串被æ å°å°ä¸ä¸ª varchar(255)ç±»åï¼åå³äºæ°æ®åºç±»åï¼ã æ°å被æ å°å°ä¸ä¸ªç±»ä¼¼æ´æ°ç±»åï¼åå³äºæ°æ®åºç±»åï¼ã使¯æä»¬ä¸å¸æææçå齿¯æéç varchars ææ´æ°ï¼è®©æä»¬ä¿®æ¹ä¸ä»£ç 以设置æ³è¦çæ°æ®ç±»åï¼
import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 100
})
name: string;
@Column("text")
description: string;
@Column()
filename: string;
@Column("double")
views: number;
@Column()
isPublished: boolean;
}
åç±»åæ¯ç¹å®äºæ°æ®åºçãä½ å¯ä»¥è®¾ç½®æ°æ®åºæ¯æçä»»ä½åç±»åãæå ³æ¯æçåç±»åçæ´å¤ä¿¡æ¯ï¼è¯·åè§æ¤å¤ã
åå»ºæ°æ®åºçè¿æ¥â
å½å®ä½è¢«å建åï¼è®©æä»¬å建ä¸ä¸ªindex.tsï¼æapp.tsï¼æ è®ºä½ æä¹å½åï¼æä»¶ï¼å¹¶é
ç½®æ°æ®åºè¿æ¥ï¼:
import "reflect-metadata";
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test",
entities: [Photo],
synchronize: true,
logging: false
})
.then(connection => {
// è¿éå¯ä»¥åå®ä½æä½ç¸å
³ç代ç
})
.catch(error => console.log(error));
æä»¬å¨æ¤ç¤ºä¾ä¸ä½¿ç¨ MySQLï¼ä½ å¯ä»¥ä½¿ç¨ä»»ä½å
¶ä»åæ¯æçæ°æ®åºãè¦ä½¿ç¨å
¶ä»æ°æ®åºï¼åªéå°é项ä¸çtypeæ´æ¹ä¸ºå¸æä½¿ç¨çæ°æ®åºç±»åï¼mysqlï¼mariadbï¼postgresï¼sqliteï¼mssqlï¼oracleï¼cordovaï¼nativescriptï¼react-nativeï¼expo æ mongodbãåæ¶è¿è¦ç¡®ä¿ host, port, username, password åæ°æ®åºè®¾ç½®çæ£ç¡®æ§ã
æä»¬å° Photo å®ä½æ·»å å°æ¤è¿æ¥çå®ä½å表ä¸ãææéè¦å¨è¿æ¥ä¸ä½¿ç¨çæ¯ä¸ªå®ä½é½å¿ é¡»å å°è¿ä¸ªè¡¨ä¸ã
设置synchronizeå¯ç¡®ä¿æ¯æ¬¡è¿è¡åºç¨ç¨åºæ¶å®ä½é½å°ä¸æ°æ®åºåæ¥ã
å è½½ç®å½ä¸ææå®ä½â
ä¹å彿们å建æ´å¤å®ä½æ¶ï¼é½éè¦å°ä¸ä¸å®ä»¬æ·»å å°é ç½®ä¸çå®ä½ä¸ï¼ä½æ¯è¿ä¸æ¯å¾æ¹ä¾¿ï¼æä»¥æä»¬å¯ä»¥è®¾ç½®æ´ä¸ªç®å½ï¼ä»ä¸è¿æ¥ææå®ä½å¹¶å¨è¿æ¥ä¸ä½¿ç¨ï¼
import { createConnection } from "typeorm";
createConnection({
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test",
entities: [__dirname + "/entity/*.js"],
synchronize: true
})
.then(connection => {
// è¿éå¯ä»¥åå®ä½æä½ç¸å
³ç代ç
})
.catch(error => console.log(error));
ä½è¦å°å¿è¿ç§æ¹æ³ã
å¦æä½¿ç¨çæ¯ts-nodeï¼åéè¦æå®.tsæä»¶çè·¯å¾ã
å¦æä½¿ç¨çæ¯outDirï¼é£ä¹éè¦å¨outDirç®å½ä¸æå®.jsæä»¶çè·¯å¾ã
å¦æä½¿ç¨outDirï¼å½ä½ å 餿éå½åå®ä½æ¶ï¼è¯·ç¡®ä¿æ¸
é¤outDirç®å½å¹¶åæ¬¡éæ°ç¼è¯é¡¹ç®ï¼å 为å½ä½ å é¤.tsæºæä»¶æ¶ï¼å
¶ç¼è¯ç.jsçæ¬ä¸ä¼ä»è¾åºç®å½ä¸å é¤,å¹¶ä¸ TypeORM ä¾ç¶ä¼ä»outDirä¸å è½½è¿äºæä»¶ï¼ä»è导è´å¼å¸¸ã
å¯å¨åºç¨â
ç°å¨å¯ä»¥å¯å¨app.tsï¼å¯å¨åå¯ä»¥åç°æ°æ®åºèªå¨è¢«åå§åï¼å¹¶ä¸ Photo è¿ä¸ªè¡¨ä¹ä¼åå»ºåºæ¥ã
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(500) | |
| description | text | |
| filename | varchar(255) | |
| views | int(11) | |
| isPublished | boolean | |
+-------------+--------------+----------------------------+
æ·»å åæå ¥ photoâ
ç°å¨å建ä¸ä¸ªæ°ç photo åå°æ°æ®åºï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
return connection.manager.save(photo).then(photo => {
console.log("Photo has been saved. Photo id is", photo.id);
});
})
.catch(error => console.log(error));
ä¿åå®ä½åï¼å®å°è·å¾æ°çæç IDã saveæ¹æ³è¿åä¼ éç»å®çåä¸å¯¹è±¡çå®ä¾ãä½å®ä¸æ¯å¯¹è±¡çæ°å¯æ¬ï¼åªæ¯ä¿®æ¹äºå®ç"id"å¹¶è¿åå®ã
ä½¿ç¨ async/await è¯æ³â
æä»¬å¯ä»¥ä½¿ç¨ææ°ç ES8ï¼ES2017ï¼åè½ï¼å¹¶ä½¿ç¨ async / await è¯æ³ä»£æ¿ï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
await connection.manager.save(photo);
console.log("Photo has been saved");
})
.catch(error => console.log(error));
ä½¿ç¨ Entity Managerâ
æä»¬åå建äºä¸å¼ æ° photo å¹¶å°å
¶ä¿å卿°æ®åºä¸ã使ç¨EntityManagerä½ å¯ä»¥æçºµåºç¨ä¸çä»»ä½å®ä½ã
ä¾å¦ï¼å 载已ç»ä¿åçå®ä½ï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let savedPhotos = await connection.manager.find(Photo);
console.log("All photos from the db: ", savedPhotos);
})
.catch(error => console.log(error));
savedPhotosæ¯ä¸ä¸ª Photo 对象æ°ç»ï¼å
¶ä¸å
å«ä»æ°æ®åºå è½½çæ°æ®ã
äºè§£æ´å¤æå ³ EntityManager çä¿¡æ¯ã
ä½¿ç¨ Repositoriesâ
ç°å¨è®©æä»¬éæä¹åç代ç ï¼å¹¶ä½¿ç¨Repositoryè䏿¯EntityManagerãæ¯ä¸ªå®ä½é½æèªå·±çåå¨åºï¼å¯ä»¥å¤çå
¶å®ä½çæææä½ãå½ä½ ç»å¸¸å¤çå®ä½æ¶ï¼Repositories æ¯ EntityManagers æ´æ¹ä¾¿ä½¿ç¨ï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
let photoRepository = connection.getRepository(Photo);
await photoRepository.save(photo);
console.log("Photo has been saved");
let savedPhotos = await photoRepository.find();
console.log("All photos from the db: ", savedPhotos);
})
.catch(error => console.log(error));
äºè§£æ´å¤æå ³ Repository çä¿¡æ¯ã
仿°æ®åºå è½½â
让æä»¬ä½¿ç¨ Repository å°è¯æ´å¤çå è½½æä½:
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let allPhotos = await photoRepository.find();
console.log("All photos from the db: ", allPhotos);
let firstPhoto = await photoRepository.findOne(1);
console.log("First photo from the db: ", firstPhoto);
let meAndBearsPhoto = await photoRepository.findOne({ name: "Me and Bears" });
console.log("Me and Bears photo from the db: ", meAndBearsPhoto);
let allViewedPhotos = await photoRepository.find({ views: 1 });
console.log("All viewed photos: ", allViewedPhotos);
let allPublishedPhotos = await photoRepository.find({ isPublished: true });
console.log("All published photos: ", allPublishedPhotos);
let [allPhotos, photosCount] = await photoRepository.findAndCount();
console.log("All photos: ", allPhotos);
console.log("Photos count: ", photosCount);
})
.catch(error => console.log(error));
卿°æ®åºä¸æ´æ°â
让æä»¬ä»æ°æ®åºå è½½åº photoï¼æ´æ°å¹¶ä¿åå°æ°æ®åºï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let photoToUpdate = await photoRepository.findOne(1);
photoToUpdate.name = "Me, my friends and polar bears";
await photoRepository.save(photoToUpdate);
})
.catch(error => console.log(error));
è¿ä¸ªid = 1ç photo 卿°æ®åºä¸å°±æåæ´æ°äºã
仿°æ®åºä¸å é¤â
让æä»¬ä»æ°æ®åºä¸å 餿们ç Photo:
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let photoToRemove = await photoRepository.findOne(1);
await photoRepository.remove(photoToRemove);
})
.catch(error => console.log(error));
è¿ä¸ªid = 1ç photo 卿°æ®åºä¸è¢«ç§»é¤äºã
å建ä¸å¯¹ä¸çå ³ç³»â
让æä»¬ä¸å¦ä¸ä¸ªç±»å建ä¸å¯¹ä¸çå
³ç³»ãå
å¨PhotoMetadata.tsä¸å建ä¸ä¸ªæ°ç±»ãæ¤ PhotoMetadata ç±»åºå
å« photo çå
¶ä»å
ä¿¡æ¯ï¼
import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm";
import { Photo } from "./Photo";
@Entity()
export class PhotoMetadata {
@PrimaryGeneratedColumn()
id: number;
@Column("int")
height: number;
@Column("int")
width: number;
@Column()
orientation: string;
@Column()
compressed: boolean;
@Column()
comment: string;
@OneToOne(type => Photo)
@JoinColumn()
photo: Photo;
}
è¿éæä»¬ä½¿ç¨äºä¸ä¸ªå为@OneToOneçæ°è£
饰å¨,å®å
许æä»¬å¨ä¸¤ä¸ªå®ä½ä¹é´å建ä¸å¯¹ä¸çå
³ç³»ã
type => Photoæ¯ä¸ä¸ªå½æ°ï¼è¿åæä»¬æ³è¦ä¸ä¹å»ºç«å
³ç³»çå®ä½çç±»ãç±äºç¹å®äºè¯è¨çå
³ç³»ï¼æä»¬åªè½ä½¿ç¨ä¸ä¸ªè¿åç±»ç彿°ï¼è䏿¯ç´æ¥ä½¿ç¨è¯¥ç±»ã
åæ¶ä¹å¯ä»¥æå®åæ()=> Photoï¼ä½æ¯type => Photoæ¾å¾ä»£ç æ´æå¯è¯»æ§ãtype åéæ¬èº«ä¸å
å«ä»»ä½å
容ã
æä»¬è¿æ·»å äºä¸ä¸ª@JoinColumnè£
饰å¨ï¼è¡¨æå®ä½é®ç对åºå
³ç³»ãå
³ç³»å¯ä»¥æ¯ååçæååçã使¯åªæä¸æ¹æ¯æ¥æè
ãå¨å
³ç³»çææè
æ¹é¢éè¦ä½¿ç¨@JoinColumn è£
饰å¨ã
妿è¿è¡è¯¥åºç¨ç¨åºï¼ä½ å°çå°ä¸ä¸ªæ°çæç表ï¼å®å°å å«ä¸ä¸ªå¸¦æå ³ç³»å¤é®çåï¼
+-------------+--------------+----------------------------+
| photo_metadata |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| height | int(11) | |
| width | int(11) | |
| comment | varchar(255) | |
| compressed | boolean | |
| orientation | varchar(255) | |
| photoId | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
ä¿åä¸å¯¹ä¸çå ³ç³»â
ç°å¨æ¥å建ä¸ä¸ª photoï¼å®çå ä¿¡æ¯å°å®ä»¬äºç¸è¿æ¥èµ·æ¥ã
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";
createConnection(/*...*/)
.then(async connection => {
// å建 photo
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.isPublished = true;
// å建 photo metadata
let metadata = new PhotoMetadata();
metadata.height = 640;
metadata.width = 480;
metadata.compressed = true;
metadata.comment = "cybershoot";
metadata.orientation = "portait";
metadata.photo = photo; // èæ¥ä¸¤è
// è·åå®ä½ repositories
let photoRepository = connection.getRepository(Photo);
let metadataRepository = connection.getRepository(PhotoMetadata);
// å
ä¿åphoto
await photoRepository.save(photo);
// ç¶åä¿åphotoçmetadata
await metadataRepository.save(metadata);
// 宿
console.log("Metadata is saved, and relation between metadata and photo is created in the database too");
})
.catch(error => console.log(error));
ååå ³ç³»â
å ³ç³»å¯ä»¥æ¯ååçæååçãç®å PhotoMetadata å Photo ä¹é´çå ³ç³»æ¯ååçãå ³ç³»çææè æ¯ PhotoMetadataï¼è Photo 对 PhotoMetadata 䏿 æç¥ãè¿ä½¿å¾ä» Photo ä¸è®¿é® PhotoMetadata åå¾å¾å¤æãè¦è§£å³è¿ä¸ªé®é¢ï¼æä»¬åºè¯¥å¨ PhotoMetadata å Photo ä¹é´å»ºç«ååå ³ç³»ã让æä»¬æ¥ä¿®æ¹ä¸ä¸å®ä½ï¼
import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm";
import { Photo } from "./Photo";
@Entity()
export class PhotoMetadata {
/* ... other columns */
@OneToOne(type => Photo, photo => photo.metadata)
@JoinColumn()
photo: Photo;
}
import { Entity, Column, PrimaryGeneratedColumn, OneToOne } from "typeorm";
import { PhotoMetadata } from "./PhotoMetadata";
@Entity()
export class Photo {
/* ... other columns */
@OneToOne(type => PhotoMetadata, photoMetadata => photoMetadata.photo)
metadata: PhotoMetadata;
}
photo => photo.metadataæ¯ç¨æ¥æå®ååå
³ç³»çåç§°ãPhoto ç±»çå
æ°æ®å±æ§æ¯å¨ Photo ç±»ä¸åå¨ PhotoMetadata çå°æ¹ãä½ å¯ä»¥éæ©ç®åå°å°åç¬¦ä¸²ä¼ éç»@OneToOneè£
饰å¨ï¼è䏿¯ä¼ éè¿å photo 屿§ç彿°ï¼ä¾å¦"metadata"ãè¿ç§å½æ°ç±»åçæ¹æ³ä½¿æä»¬çéææ´å®¹æã
注æï¼æä»¬åºè¯¥ä»
å¨å
³ç³»çä¸ä¾§ä½¿ç¨@JoinColumnè£
饰å¨ãä½ æè¿ä¸ªè£
饰è
æ¾å¨åªä¸æ¹å°æ¯è¿æ®µå
³ç³»çæ¥ææ¹ãå
³ç³»çæ¥ææ¹å
嫿°æ®åºä¸å
·æå¤é®çåã
ååºå ³ç³»å¯¹è±¡çæ°æ®â
å¨ä¸ä¸ªæ¥è¯¢ä¸å è½½ photo å photo metadata æä¸¤ç§æ¹æ³ã使ç¨find *æä½¿ç¨QueryBuilderãæä»¬å
使ç¨find *æ¹æ³ã find *æ¹æ³å
è®¸ä½ ä½¿ç¨FindOneOptions / FindManyOptionsæ¥å£æå®å¯¹è±¡ã
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let photoRepository = connection.getRepository(Photo);
let photos = await photoRepository.find({ relations: ["metadata"] });
})
.catch(error => console.log(error));
photos å°å 嫿¥èªæ°æ®åºç photos æ°ç»ï¼æ¯ä¸ª photo å°å å«å ¶ photo metadataã详ç»äºè§£æ¬ææ¡£ä¸çæ¥æ¾é项ã
ä½¿ç¨æ¥æ¾é项å¾ç®åï¼ä½æ¯å¦æä½ éè¦æ´å¤æçæ¥è¯¢ï¼ååºè¯¥ä½¿ç¨QueryBuilderã QueryBuilderå
许以æ´ä¼é
çæ¹å¼ä½¿ç¨æ´å¤æçæ¥è¯¢ï¼
import { createConnection } from "typeorm";
import { Photo } from "./entity/Photo";
import { PhotoMetadata } from "./entity/PhotoMetadata";
createConnection(/*...*/)
.then(async connection => {
/*...*/
let photos = await connection
.getRepository(Photo)
.createQueryBuilder("photo")
.innerJoinAndSelect("photo.metadata", "metadata")
.getMany();
})
.catch(error => console.log(error));
QueryBuilderå
许åå»ºåæ§è¡å ä¹ä»»ä½å¤ææ§ç SQL æ¥è¯¢ã使ç¨QueryBuilderæ¶ï¼è¯·èèå建 SQL æ¥è¯¢ã卿¤ç¤ºä¾ä¸ï¼"photo"å"metadata"æ¯åºç¨äºæé photos ç ââ å«åãä½ å¯ä»¥ä½¿ç¨å«åæ¥è®¿é®æéæ°æ®çåå屿§ã
ä½¿ç¨ cascades èªå¨ä¿åç¸å ³å¯¹è±¡â
æä»¬å¯ä»¥å¨å
³ç³»ä¸è®¾ç½®cascadeé项ï¼è¿æ¯å°±å¯ä»¥å¨ä¿åå
¶ä»å¯¹è±¡çåæ¶ä¿åç¸å
³å¯¹è±¡ã让æä»¬æ´æ¹ä¸ä¸ç photo ç@OneToOneè£
饰å¨ï¼
export class Photo {
/// ... other columns
@OneToOne(type => PhotoMetadata, metadata => metadata.photo, {
cascade: true
})
metadata: PhotoMetadata;
}
使ç¨cascadeå
许就ä¸éè¦è¾¹å photo è¾¹åå
æ°æ®å¯¹è±¡ãæä»¬å¯ä»¥ç®åå°ä¿åä¸ä¸ª photo 对象ï¼ç±äºä½¿ç¨äº cascadeï¼metadata ä¹å°èªå¨ä¿åã
createConnection(options)
.then(async connection => {
// å建 photo 对象
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.isPublished = true;
// å建 photo metadata 对象
let metadata = new PhotoMetadata();
metadata.height = 640;
metadata.width = 480;
metadata.compressed = true;
metadata.comment = "cybershoot";
metadata.orientation = "portait";
photo.metadata = metadata; // this way we connect them
// è·å repository
let photoRepository = connection.getRepository(Photo);
// ä¿åphotoçåæ¶ä¿åmetadata
await photoRepository.save(photo);
console.log("Photo is saved, photo metadata is saved too.");
})
.catch(error => console.log(error));
å建å¤å¯¹ä¸/ä¸å¯¹å¤å ³ç³»â
让æä»¬å建ä¸ä¸ªå¤å¯¹ä¸/ä¸å¯¹å¤çå
³ç³»ãå设ä¸ä¸ª photo æä¸ä¸ª authorï¼æ¯ä¸ª author é½å¯ä»¥æå¤ä¸ª photosãé¦å
让æä»¬å建ä¸ä¸ªAuthorç±»ï¼
import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm";
import { Photo } from "./Photo";
@Entity()
export class Author {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(type => Photo, photo => photo.author) // note: we will create author property in the Photo class below
photos: Photo[];
}
Author å
å«ååå
³ç³»ã
OneToMany æ»æ¯ååç, 并䏿»æ¯ä¸ ManyToOneä¸èµ·åºç°ã
ç°å¨è®©æä»¬å°å ³ç³»çææè æ¹æ·»å å° Photo å®ä½ä¸ï¼
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm";
import { PhotoMetadata } from "./PhotoMetadata";
import { Author } from "./Author";
@Entity()
export class Photo {
/* ... other columns */
@ManyToOne(type => Author, author => author.photos)
author: Author;
}
å¨å¤å¯¹ä¸/ä¸å¯¹å¤çå
³ç³»ä¸ï¼æ¥ææ¹æ»æ¯å¤å¯¹ä¸çãè¿æå³ç使ç¨@ManyToOneçç±»å°åå¨ç¸å
³å¯¹è±¡ç idã
è¿è¡åºç¨ç¨åºåï¼ORM å°å建author表ï¼
+-------------+--------------+----------------------------+
| author |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
å®è¿å°ä¿®æ¹photoè¡¨ï¼æ·»å æ°çauthorå并为å
¶å建å¤é®ï¼
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
| description | varchar(255) | |
| filename | varchar(255) | |
| isPublished | boolean | |
| authorId | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
å建å¤å¯¹å¤å ³ç³»â
å设ä¸ä¸ª photo å¯ä»¥æ¾å¨å¤ä¸ª albums ä¸ï¼æ¯ä¸ª albums å¯ä»¥å
å«å¤ä¸ª photoã让æä»¬å建ä¸ä¸ªAlbumç±»ï¼
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";
@Entity()
export class Album {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(type => Photo, photo => photo.albums)
@JoinTable()
photos: Photo[];
}
@JoinTableéè¦æå®è¿æ¯å
³ç³»çææè
æ¹ã
ç°å¨æ·»å ååå
³ç³»å°Photoç±»ï¼
export class Photo {
/// ... other columns
@ManyToMany(type => Album, album => album.photos)
albums: Album[];
}
è¿è¡åï¼ORM å°å建album_photos_photo_albums_èç»è¡¨ã
+-------------+--------------+----------------------------+
| album_photos_photo_albums |
+-------------+--------------+----------------------------+
| album_id | int(11) | PRIMARY KEY FOREIGN KEY |
| photo_id | int(11) | PRIMARY KEY FOREIGN KEY |
+-------------+--------------+----------------------------+
è®°å¾å¨ ORM ä¸ä½¿ç¨ ConnectionOptions 注åAlbumç±»ï¼
const options: ConnectionOptions = {
// ... other options
entities: [Photo, PhotoMetadata, Author, Album]
};
ç°å¨è®©æä»¬å° albums å photos æå ¥æä»¬çæ°æ®åº:
let connection = await createConnection(options);
// create a few albums
let album1 = new Album();
album1.name = "Bears";
await connection.manager.save(album1);
let album2 = new Album();
album2.name = "Me";
await connection.manager.save(album2);
// create a few photos
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.albums = [album1, album2];
await connection.manager.save(photo);
// now our photo is saved and albums are attached to it
// now lets load them:
const loadedPhoto = await connection.getRepository(Photo).findOne(1, { relations: ["albums"] });
loadedPhoto å¦ä¸æç¤º:
{
id: 1,
name: "Me and Bears",
description: "I am near polar bears",
filename: "photo-with-bears.jpg",
albums: [{
id: 1,
name: "Bears"
}, {
id: 2,
name: "Me"
}]
}
ä½¿ç¨ QueryBuilderâ
ä½ å¯ä»¥ä½¿ç¨ QueryBuilder æå»ºå ä¹ä»»ä½å¤ææ§ç SQL æ¥è¯¢ãä¾å¦ï¼å¯ä»¥è¿æ ·åï¼
let photos = await connection
.getRepository(Photo)
.createQueryBuilder("photo") // first argument is an alias. Alias is what you are selecting - photos. You must specify it.
.innerJoinAndSelect("photo.metadata", "metadata")
.leftJoinAndSelect("photo.albums", "album")
.where("photo.isPublished = true")
.andWhere("(photo.name = :photoName OR photo.name = :bearName)")
.orderBy("photo.id", "DESC")
.skip(5)
.take(10)
.setParameters({ photoName: "My", bearName: "Mishka" })
.getMany();
æ¤æ¥è¯¢éæ©ææ published ç name çäº"My"æ"Mishka"ç photosãå®å°ä»ç»æä¸ç第 5 个ï¼å页åç§»ï¼å¼å§ï¼å¹¶ä¸ä» éæ© 10 ä¸ªç»æï¼å页éå¶ï¼ãå¾å°çç»æå°æ ID éåºæåºãphoto ç albums å°è¢« left-joinedï¼å ¶å æ°æ®å°è¢« inner joinedã
ç±äº QueryBuilder çèªç±åº¦æ´é«ï¼å æ¤å¨é¡¹ç®ä¸å¯è½ä¼å¤§éç使ç¨å®ã æ´å¤å ³äº QueryBuilder çä¿¡æ¯ï¼å¯æ¥çã
示ä¾â
æ¥ç示ä¾ç¨æ³ã
ä¸é¢è¿äº repositories å¯ä»¥å¸®å©ä½ å¿«éå¼å§ï¼
- Example how to use TypeORM with TypeScript
- Example how to use TypeORM with JavaScript
- Example how to use TypeORM with JavaScript and Babel
- Example how to use TypeORM with TypeScript and SystemJS in Browser
- Example how to use Express and TypeORM
- Example how to use Koa and TypeORM
- Example how to use TypeORM with MongoDB
- Example how to use TypeORM in a Cordova/PhoneGap app
- Example how to use TypeORM with an Ionic app
- Example how to use TypeORM with React Native
- Example how to use TypeORM with Electron using JavaScript
- Example how to use TypeORM with Electron using TypeScript
æ©å±â
è¿å 个æ©å±å¯ä»¥ç®å TypeORM ç使ç¨ï¼å¹¶å°å ¶ä¸å ¶ä»æ¨¡åéæï¼
- TypeORM + GraphQL framework
- TypeORM integration with TypeDI
- TypeORM integration with routing-controllers
- ä»ç°ææ°æ®åºçææ¨¡å - typeorm-model-generator
è´¡ç®â
äºè§£å¦ä½è´¡ç®è¿é以åå¦ä½è®¾ç½®å¼åç¯å¢[è¿é](https://github.com/typeorm/typeorm/blob/master/ DEVELOPER.md)ã
æè°¢ææè´¡ç®è ï¼
èµå©åâ
弿ºæ¢å°é¾åèæ¶ã å¦æä½ æ³æèµ TypeORM çæªæ¥ï¼ä½ å¯ä»¥æä¸ºèµå©åï¼è®©æä»¬çæ ¸å¿å¢éè±æ´å¤æ¶é´å¨ TypeORM çæ¹è¿åæ°åè½ä¸ãæä¸ºèµå©å
éçèµå©åâ
æä¸ºéçèµå©åï¼å¹¶ä»æä»¬çæ ¸å¿è´¡ç®è é£éè·å¾é«çº§ææ¯æ¯æã æä¸ºéçèµå©å
