TypeOmm是一個可以在Nodejs,瀏覽器,Cordova,Phonegap,Ionic,React Native,NativeScript,Expo和Electron Platforms中運行的ORM,並且可以與Typescript和JavaScript(ES2021)一起使用。它的目標是始終支持最新的JavaScript功能,並提供其他功能,以幫助您開發使用數據庫的任何類型的應用程序 - 從具有幾個表格的小應用程序到具有多個數據庫的大型企業應用程序。
與當前存在的所有其他JavaScript ORM不同,TypeOmm支持主動記錄和數據映射器模式,這意味著您可以以最有生產力的方式編寫高質量,鬆散,可擴展,可維護的應用程序。
TypeOmm受其他ORM的影響很大,例如冬眠,學說和實體框架。
公告:Typeorm的未來
我們很高興分享我們對振興的型號的願景,這是一種旨在為長期建立穩定,健壯和可持續的基礎的戰略。了解我們如何結構維護並將專用資源匯總在一起,以確保Typeorm在未來幾年中蓬勃發展。
閱讀完整的公告
還有更多...
使用Typeorm,您的模型看起來像這樣:
import { Entity , PrimaryGeneratedColumn , Column } from "typeorm"
@ Entity ( )
export class User {
@ PrimaryGeneratedColumn ( )
id : number
@ Column ( )
firstName : string
@ Column ( )
lastName : string
@ Column ( )
age : number
}
和您的域邏輯看起來像這樣:
const userRepository = MyDataSource . getRepository ( User )
const user = new User ( )
user . firstName = "Timber"
user . lastName = "Saw"
user . age = 25
await userRepository . save ( user )
const allUsers = await userRepository . find ( )
const firstUser = await userRepository . findOneBy ( {
id : 1 ,
} ) // find by id
const timber = await userRepository . findOneBy ( {
firstName : "Timber" ,
lastName : "Saw" ,
} ) // find by firstName and lastName
await userRepository . 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 . findOneBy ( {
id : 1 ,
} )
const timber = await User . findOneBy ( {
firstName : "Timber" ,
lastName : "Saw"
} )
await timber . remove ( )
安裝NPM軟件包:
npm install typeorm --save
您需要安裝reflect-metadata
墊片:
npm install reflect-metadata --save
並將其導入應用程序的全局位置(例如在app.ts
中):
import "reflect-metadata"
您可能需要安裝節點鍵入:
npm install @types/node --save-dev
安裝數據庫驅動程序:
對於MySQL或Mariadb
npm install mysql --save
(您也可以安裝mysql2
)
用於postgresql或cockroackdb
npm install pg --save
對於sqlite
npm install sqlite3 --save
對於Microsoft SQL Server
npm install mssql --save
對於sql.js
npm install sql.js --save
對於Oracle
npm install oracledb --save
為了使Oracle驅動程序正常工作,您需要按照其網站的安裝說明進行操作。
對於SAP HANA
npm install @sap/hana-client
npm install hdb-pool
SAP HANA支持由Neptune軟件的讚助成為可能。
對於Google Cloud Spanner
npm install @google-cloud/spanner --save
通過設置環境變量GOOGLE_APPLICATION_CREDENTIALS
來為您的應用程序代碼提供身份驗證憑證:
# Linux/macOS
export GOOGLE_APPLICATION_CREDENTIALS= " KEY_PATH "
# Windows
set GOOGLE_APPLICATION_CREDENTIALS=KEY_PATH
# Replace KEY_PATH with the path of the JSON file that contains your service account key.
要將Spanner與模擬器一起使用,請設置SPANNER_EMULATOR_HOST
環境變量:
# Linux/macOS
export SPANNER_EMULATOR_HOST=localhost:9010
# Windows
set SPANNER_EMULATOR_HOST=localhost:9010
對於蒙古(實驗)
npm install mongodb@^5.2.0 --save
對於nimentscript ,反應本和科爾多瓦
檢查支持平台的文檔
僅安裝其中一個,具體取決於您使用的數據庫。
另外,請確保您正在使用Typescript版本4.5或更高版本,並且您已在tsconfig.json
中啟用了以下設置:
"emitDecoratorMetadata" : true ,
"experimentalDecorators" : true ,
您可能還需要在編譯器選項的lib
部分中啟用es6
,或從@types
安裝es6-shim
。
開始使用TypeOmm的最快方法是使用其CLI命令來生成一個入門項目。快速啟動僅在nodejs應用程序中使用typeorm時才能起作用。如果您使用其他平台,請繼續訪問分步指南。
要使用CLI創建一個新項目,請運行以下命令:
npx typeorm init --name MyProject --database postgres
name
是項目的名稱, database
是您使用的數據庫。數據庫可以是以下值之一: mysql
, mariadb
, postgres
, cockroachdb
, sqlite
, mssql
, sap
, spanner
,SPANNER, oracle
, mongodb
,MONGODB, cordova
,CORDOVA,REACT react-native
NATIVEN,REACT-NATICATION,EXPO, expo
, nativescript
。
此命令將在MyProject
目錄中生成一個新項目,並使用以下文件:
MyProject
├── src // place of your TypeScript code
│ ├── entity // place where your entities (database models) are stored
│ │ └── User.ts // sample entity
│ ├── migration // place where your migrations are stored
│ ├── data-source.ts // data source and all connection configuration
│ └── index.ts // start point of your application
├── .gitignore // standard gitignore file
├── package.json // node module dependencies
├── README.md // simple readme file
└── tsconfig.json // TypeScript compiler options
您還可以在現有節點項目上運行
typeorm init
,但要小心 - 它可能會覆蓋您已經擁有的某些文件。
下一步是安裝新的項目依賴項:
cd MyProject
npm install
安裝了所有依賴關係後,請編輯data-source.ts
文件,然後將您自己的數據庫連接配置選項放在其中:
export const AppDataSource = new DataSource ( {
type : "postgres" ,
host : "localhost" ,
port : 5432 ,
username : "test" ,
password : "test" ,
database : "test" ,
synchronize : true ,
logging : true ,
entities : [ Post , Category ] ,
subscribers : [ ] ,
migrations : [ ] ,
} )
特別是在大多數情況下,您只需要配置host
, username
, password
, database
以及port
選項即可。
完成配置並安裝了所有節點模塊後,您就可以運行您的應用程序:
npm start
就是這樣,您的應用程序應成功運行並將新用戶插入數據庫。您可以繼續使用此項目,並整合所需的其他模塊並開始創建更多實體。
您可以通過運行
npx typeorm init --name MyProject --database postgres --module esm
命令來生成ESM項目。
您可以通過運行
npx typeorm init --name MyProject --database mysql --express
命令來生成一個更高級的項目。
您可以通過運行
npx typeorm init --name MyProject --database postgres --docker
命令來生成docker-compose文件。
您對ORM有什麼期望?首先,您期望它將為您創建數據庫表,並查找 /插入 / update /刪除數據,而無需編寫很多幾乎無法維護的SQL查詢。本指南將向您展示如何從頭開始設置Typeorm並使其完成您從ORM期望的事情。
使用數據庫開始創建表。您如何告訴TypeOMM創建數據庫表?答案是 - 通過模型。您的應用程序中的模型是您的數據庫表。
例如,您有一個Photo
模型:
export class Photo {
id : number
name : string
description : string
filename : string
views : number
isPublished : boolean
}
您想將照片存儲在數據庫中。要將內容存儲在數據庫中,首先,您需要一個數據庫表,並且數據庫表是從模型中創建的。並非所有模型,而只有您將其定義為實體的模型。
實體是您的模型由@Entity
裝飾器裝飾。將為此類模型創建數據庫表。您與Typeorm中各地的實體合作。您可以加載/插入/更新/刪除並與它們執行其他操作。
讓我們使我們的Photo
模型成為一個實體:
import { Entity } from "typeorm"
@ Entity ( )
export class Photo {
id : number
name : string
description : string
filename : string
views : number
isPublished : boolean
}
現在,將為Photo
實體創建一個數據庫表,我們將能夠在應用程序中的任何地方使用它。我們創建了一個數據庫表,但是,沒有列可以存在哪些表?讓我們在數據庫表中創建一些列。
要添加數據庫列,您只需要用@Column
Decorator裝飾要製成的實體屬性即可。
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
to bool
等。但是,您可以通過將列類型明確指定到該數據庫類型中的任何列類型支持中@Column
Decorator。
我們生成了一個帶有列的數據庫表,但是剩下一件事。每個數據庫表必須具有帶有主鍵的列。
每個實體必須至少具有一個主密鑰列。這是一個要求,您無法避免。要使專欄成為主鍵,您需要使用@PrimaryColumn
Decorator。
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列自動生成(這被稱為自動啟動 /序列 /序列 /生成的身份列)。為此,您需要將@PrimaryColumn
裝飾器更改為@PrimaryGeneratedColumn
Decorator:
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)類型(取決於數據庫類型)。該數字映射到類似整數的類型(取決於數據庫類型)。我們不希望所有列是有限的瓦爾查爾斯或整數。讓我們設置正確的數據類型:
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
}
列類型是數據庫特定的。您可以設置數據庫支持的任何列類型。有關支持的列類型的更多信息,請參見此處。
DataSource
現在,當創建我們的實體時,讓我們創建index.ts
文件並在此處設置我們的DataSource
:
import "reflect-metadata"
import { DataSource } from "typeorm"
import { Photo } from "./entity/Photo"
const AppDataSource = new DataSource ( {
type : "postgres" ,
host : "localhost" ,
port : 5432 ,
username : "root" ,
password : "admin" ,
database : "test" ,
entities : [ Photo ] ,
synchronize : true ,
logging : false ,
} )
// to initialize the initial connection with the database, register all entities
// and "synchronize" database schema, call "initialize()" method of a newly created database
// once in your application bootstrap
AppDataSource . initialize ( )
. then ( ( ) => {
// here you can start to work with your database
} )
. catch ( ( error ) => console . log ( error ) )
在此示例中,我們正在使用Postgres,但是您可以使用任何其他支持的數據庫。要使用另一個數據庫,只需將選項中的type
更改為您正在使用的數據庫類型: mysql
, mariadb
, postgres
, cockroachdb
, sqlite
,sqlite, mssql
,oracle, oracle
, sap
, spanner
,spanner, cordova
,cordova, nativeScript, nativescript
,native-native,react-native, react-native
,exterative,exterative, expo
或mongodb
。還要確保使用自己的主機,端口,用戶名,密碼和數據庫設置。
我們將照片實體添加到此數據源的實體列表中。您在連接中使用的每個實體都必須在此處列出。
設置synchronize
確保每次運行應用程序時,您的實體都將與數據庫同步。
現在,如果您運行index.ts
,將初始化與數據庫的連接,並創建一個用於照片的數據庫表。
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(100) | |
| description | text | |
| filename | varchar(255) | |
| views | int(11) | |
| isPublished | boolean | |
+-------------+--------------+----------------------------+
現在,讓我們創建一張新照片以將其保存在數據庫中:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const 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 AppDataSource . manager . save ( photo )
console . log ( "Photo has been saved. Photo id is" , photo . id )
保存您的實體後,它將獲得新生成的ID。 save
方法返回您傳遞給它的相同對象的實例。它不是對象的新副本,它將修改其“ ID”並返回它。
我們剛剛創建了一張新照片並將其保存在數據庫中。我們使用EntityManager
保存它。使用實體管理器您可以操縱應用程序中的任何實體。例如,讓我們加載我們保存的實體:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const savedPhotos = await AppDataSource . manager . find ( Photo )
console . log ( "All photos from the db: " , savedPhotos )
savedPhotos
將是一系列照片對象,並具有從數據庫中加載的數據。
在此處了解有關EntityManager的更多信息。
現在,讓我們重構我們的代碼,並使用Repository
代替EntityManager
。每個實體都有自己的存儲庫,可以處理所有操作及其實體。當您與實體打交道很多時,存儲庫的使用比EntityManagers更方便:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const 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
const photoRepository = AppDataSource . getRepository ( Photo )
await photoRepository . save ( photo )
console . log ( "Photo has been saved" )
const savedPhotos = await photoRepository . find ( )
console . log ( "All photos from the db: " , savedPhotos )
在此處了解有關存儲庫的更多信息。
讓我們使用存儲庫嘗試更多負載操作:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const photoRepository = AppDataSource . getRepository ( Photo )
const allPhotos = await photoRepository . find ( )
console . log ( "All photos from the db: " , allPhotos )
const firstPhoto = await photoRepository . findOneBy ( {
id : 1 ,
} )
console . log ( "First photo from the db: " , firstPhoto )
const meAndBearsPhoto = await photoRepository . findOneBy ( {
name : "Me and Bears" ,
} )
console . log ( "Me and Bears photo from the db: " , meAndBearsPhoto )
const allViewedPhotos = await photoRepository . findBy ( { views : 1 } )
console . log ( "All viewed photos: " , allViewedPhotos )
const allPublishedPhotos = await photoRepository . findBy ( { isPublished : true } )
console . log ( "All published photos: " , allPublishedPhotos )
const [ photos , photosCount ] = await photoRepository . findAndCount ( )
console . log ( "All photos: " , photos )
console . log ( "Photos count: " , photosCount )
現在,讓我們從數據庫中加載一張照片,對其進行更新並保存:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const photoRepository = AppDataSource . getRepository ( Photo )
const photoToUpdate = await photoRepository . findOneBy ( {
id : 1 ,
} )
photoToUpdate . name = "Me, my friends and polar bears"
await photoRepository . save ( photoToUpdate )
現在,帶有id = 1
照片將在數據庫中更新。
現在,讓我們從數據庫中刪除我們的照片:
import { Photo } from "./entity/Photo"
import { AppDataSource } from "./index"
const photoRepository = AppDataSource . getRepository ( Photo )
const photoToRemove = await photoRepository . findOneBy ( {
id : 1 ,
} )
await photoRepository . remove ( photoToRemove )
現在,帶有id = 1
照片將從數據庫中刪除。
讓我們與另一類建立一對一的關係。讓我們在PhotoMetadata.ts
中創建一個新類。該光最大的類應該包含我們照片的附加元信息:
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 ( ( ) => Photo )
@ JoinColumn ( )
photo : Photo
}
在這裡,我們正在使用一個名為@OneToOne
的新裝飾器。它使我們能夠在兩個實體之間建立一對一的關係。 type => Photo
是返回我們想要與之建立關係的實體類別的函數。由於語言細節,我們被迫使用返回類的函數,而不是直接使用類。我們還可以將其寫為() => Photo
,但是我們使用type => Photo
作為約定來增加代碼可讀性。類型變量本身不包含任何內容。
我們還添加了一個@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 |
+-------------+--------------+----------------------------+
現在,讓我們保存一張照片及其元數據,並將它們互相連接。
import { Photo } from "./entity/Photo"
import { PhotoMetadata } from "./entity/PhotoMetadata"
// create a photo
const 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
// create a photo metadata
const metadata = new PhotoMetadata ( )
metadata . height = 640
metadata . width = 480
metadata . compressed = true
metadata . comment = "cybershoot"
metadata . orientation = "portrait"
metadata . photo = photo // this way we connect them
// get entity repositories
const photoRepository = AppDataSource . getRepository ( Photo )
const metadataRepository = AppDataSource . getRepository ( PhotoMetadata )
// first we should save a photo
await photoRepository . save ( photo )
// photo is saved. Now we need to save a photo metadata
await metadataRepository . save ( metadata )
// done
console . log (
"Metadata is saved, and the relation between metadata and photo is created in the database too" ,
)
關係可以是單向或雙向的。當前,我們在光載和照片之間的關係是單向的。關係的所有者是Photometadata,照片對Photmetadata一無所知。這使得從照片側訪問Photmetadata變得複雜。為了解決此問題,我們應該添加一個反關係,並在光度計和照片雙向之間建立關係。讓我們修改我們的實體:
import {
Entity ,
Column ,
PrimaryGeneratedColumn ,
OneToOne ,
JoinColumn ,
} from "typeorm"
import { Photo } from "./Photo"
@ Entity ( )
export class PhotoMetadata {
/* ... other columns */
@ OneToOne ( ( ) => 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 ( ( ) => PhotoMetadata , ( photoMetadata ) => photoMetadata . photo )
metadata : PhotoMetadata
}
photo => photo.metadata
是返回關係逆側的名稱的函數。在這裡,我們證明了照片類的元數據屬性是我們在照片類中存儲Photometadata的地方。您可以簡單地將字符串傳遞給@OneToOne
Decorator,例如"metadata"
,而不是傳遞返回照片屬性的函數。但是我們使用這種功能型方法來使我們的重構更容易。
請注意,我們應該僅在關係的一側使用@JoinColumn
裝飾器。無論您將該裝飾師放在哪個方面,都將是關係的自然一面。關係的自有側包含數據庫中帶有外鍵的列。
如果您在打字稿項目中使用ESM,則應在關係屬性中使用Relation
包裝器類型,以避免循環依賴性問題。讓我們修改我們的實體:
import {
Entity ,
Column ,
PrimaryGeneratedColumn ,
OneToOne ,
JoinColumn ,
Relation ,
} from "typeorm"
import { Photo } from "./Photo"
@ Entity ( )
export class PhotoMetadata {
/* ... other columns */
@ OneToOne ( ( ) => Photo , ( photo ) => photo . metadata )
@ JoinColumn ( )
photo : Relation < Photo >
}
import {
Entity ,
Column ,
PrimaryGeneratedColumn ,
OneToOne ,
Relation ,
} from "typeorm"
import { PhotoMetadata } from "./PhotoMetadata"
@ Entity ( )
export class Photo {
/* ... other columns */
@ OneToOne ( ( ) => PhotoMetadata , ( photoMetadata ) => photoMetadata . photo )
metadata : Relation < PhotoMetadata >
}
現在,讓我們將照片及其照片元數據加載到一個查詢中。有兩種方法可以做到 - 使用find*
方法或使用QueryBuilder
功能。讓我們首先使用find*
方法。 find*
方法允許您使用FindOneOptions
/ FindManyOptions
接口指定對象。
import { Photo } from "./entity/Photo"
import { PhotoMetadata } from "./entity/PhotoMetadata"
import { AppDataSource } from "./index"
const photoRepository = AppDataSource . getRepository ( Photo )
const photos = await photoRepository . find ( {
relations : {
metadata : true ,
} ,
} )
在這裡,照片將包含數據庫中的一系列照片,每張照片都包含其照片元數據。在此文檔中了解有關查找選項的更多信息。
使用查找選項很簡單,但很簡單,但是如果您需要更複雜的查詢,則應改用QueryBuilder
。 QueryBuilder
允許以優雅的方式使用更複雜的查詢:
import { Photo } from "./entity/Photo"
import { PhotoMetadata } from "./entity/PhotoMetadata"
import { AppDataSource } from "./index"
const photos = await AppDataSource . getRepository ( Photo )
. createQueryBuilder ( "photo" )
. innerJoinAndSelect ( "photo.metadata" , "metadata" )
. getMany ( )
QueryBuilder
允許創建和執行幾乎任何復雜性的SQL查詢。當您使用QueryBuilder
時,請像創建SQL查詢一樣思考。在此示例中,“照片”和“元數據”是應用於選定照片的別名。您使用別名訪問所選數據的列和屬性。
我們可以在關係中設置級聯選項,如果我們希望在保存另一個對象時保存相關對象。讓我們稍微更改照片的@OneToOne
裝飾儀:
export class Photo {
// ... other columns
@ OneToOne ( ( ) => PhotoMetadata , ( metadata ) => metadata . photo , {
cascade : true ,
} )
metadata : PhotoMetadata
}
使用cascade
使我們現在不得立即保存照片並分別保存元數據對象。現在,我們可以簡單地保存一個照片對象,並且由於級聯選項,將自動保存元數據對象。
import { AppDataSource } from "./index"
// create photo object
const photo = new Photo ( )
photo . name = "Me and Bears"
photo . description = "I am near polar bears"
photo . filename = "photo-with-bears.jpg"
photo . isPublished = true
// create photo metadata object
const metadata = new PhotoMetadata ( )
metadata . height = 640
metadata . width = 480
metadata . compressed = true
metadata . comment = "cybershoot"
metadata . orientation = "portrait"
photo . metadata = metadata // this way we connect them
// get repository
const photoRepository = AppDataSource . getRepository ( Photo )
// saving a photo also save the metadata
await photoRepository . save ( photo )
console . log ( "Photo is saved, photo metadata is saved too." )
請注意,我們現在設置了照片的metadata
屬性,而不是像以前一樣而不是元數據的photo
屬性。 cascade
功能僅在將照片從照片的一側連接到其元數據時才有效。如果設置元數據側,則不會自動保存元數據。
讓我們創建一個多對一/一對一的關係。假設一張照片有一個作者,每個作者都可以有很多照片。首先,讓我們創建一個Author
班:
import {
Entity ,
Column ,
PrimaryGeneratedColumn ,
OneToMany ,
JoinColumn ,
} from "typeorm"
import { Photo } from "./Photo"
@ Entity ( )
export class Author {
@ PrimaryGeneratedColumn ( )
id : number
@ Column ( )
name : string
@ OneToMany ( ( ) => Photo , ( photo ) => photo . author ) // note: we will create author property in the Photo class below
photos : Photo [ ]
}
Author
包含關係的反面。 OneToMany
始終是關係的反面,並且在關係的另一側沒有ManyToOne
。
現在,讓我們將關係的所有者側添加到照片實體中:
import { Entity , Column , PrimaryGeneratedColumn , ManyToOne } from "typeorm"
import { PhotoMetadata } from "./PhotoMetadata"
import { Author } from "./Author"
@ Entity ( )
export class Photo {
/* ... other columns */
@ ManyToOne ( ( ) => 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 |
+-------------+--------------+----------------------------+
讓我們建立一個多一的關係。假設一張照片可以在許多專輯中,每張專輯都可以包含許多照片。讓我們創建一個Album
類:
import {
Entity ,
PrimaryGeneratedColumn ,
Column ,
ManyToMany ,
JoinTable ,
} from "typeorm"
@ Entity ( )
export class Album {
@ PrimaryGeneratedColumn ( )
id : number
@ Column ( )
name : string
@ ManyToMany ( ( ) => Photo , ( photo ) => photo . albums )
@ JoinTable ( )
photos : Photo [ ]
}
需要@JoinTable
來指定這是關係的所有者方。
現在,讓我們添加我們與Photo
類的關係的倒數:
export class Photo {
// ... other columns
@ ManyToMany ( ( ) => Album , ( album ) => album . photos )
albums : Album [ ]
}
運行應用程序後,ORM將創建一個prolem_photos_photo_albums enction表:
+-------------+--------------+----------------------------+
| album_photos_photo_albums |
+-------------+--------------+----------------------------+
| album_id | int(11) | PRIMARY KEY FOREIGN KEY |
| photo_id | int(11) | PRIMARY KEY FOREIGN KEY |
+-------------+--------------+----------------------------+
不要忘記在ORM中使用您的連接註冊Album
類:
const options : DataSourceOptions = {
// ... other options
entities : [ Photo , PhotoMetadata , Author , Album ] ,
}
現在,讓我們將相冊和照片插入我們的數據庫中:
import { AppDataSource } from "./index"
// create a few albums
const album1 = new Album ( )
album1 . name = "Bears"
await AppDataSource . manager . save ( album1 )
const album2 = new Album ( )
album2 . name = "Me"
await AppDataSource . manager . save ( album2 )
// create a few photos
const 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
photo . albums = [ album1 , album2 ]
await AppDataSource . manager . save ( photo )
// now our photo is saved and albums are attached to it
// now lets load them:
const loadedPhoto = await AppDataSource . getRepository ( Photo ) . findOne ( {
where : {
id : 1 ,
} ,
relations : {
albums : true ,
} ,
} )
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構建幾乎任何復雜性的SQL查詢。例如,您可以做到這一點:
const photos = await AppDataSource . 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 ( )
此查詢選擇所有已發布的照片都以“我的”或“ Mishka”名稱。它將從位置5(分頁偏移)中選擇結果,僅選擇10個結果(分頁限制)。選擇結果將按照降序訂購。相冊將加入,他們的元數據將加入。
您將在您的應用程序中使用查詢構建器。在此處了解有關QueryBuilder的更多信息。
查看樣品中的樣本以獲取使用示例。
有一些存儲庫可以克隆並從:
有幾種擴展可以簡化使用TypeOmm並將其集成到其他模塊:
data-source.ts
。relations
對象 - 類型摩托關係relations
在此處了解貢獻以及如何在此處建立您的開發環境。
該項目的存在得益於所有貢獻的人:
開源很難且耗時。如果您想投資Typeorm的未來,您可以成為贊助商,並讓我們的核心團隊在TypeOmm的改進和新功能上花費更多的時間。成為贊助商
成為黃金贊助商,並從我們的核心貢獻者那裡獲得高級技術支持。成為黃金贊助商