Typeormは、nodejs、ブラウザー、Cordova、Phonegap、Ionic、React Native、nativecript、expo、およびElectronプラットフォームで実行できるORMであり、TypeScriptおよびJavaScript(ES2021)で使用できます。その目標は、最新のJavaScript機能を常にサポートし、いくつかのテーブルを備えた小さなアプリケーションから複数のデータベースを持つ大規模なエンタープライズアプリケーションまで、データベースを使用するあらゆる種類のアプリケーションを開発するのに役立つ追加機能を提供することです。
Typeormは、現在存在している他のすべてのJavaScript ORMとは異なり、アクティブレコードとデータマッパーパターンの両方をサポートします。つまり、最も生産的な方法で高品質でゆるく結合された、スケーラブルな、保守可能なアプリケーションを作成できます。
Typeormは、Hibernate、Doctrine、Entity Frameworkなど、他のOMの影響を強く受けています。
発表:Typeormの未来
私たちは、活性化された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またはCockRoachDBの場合
npm install pg --save
sqlite用
npm install sqlite3 --save
Microsoft SQL Server用
npm install mssql --save
sql.jsの場合
npm install sql.js --save
オラクルのために
npm install oracledb --save
Oracleドライバーを機能させるには、サイトからのインストール手順に従う必要があります。
SAP HANAの場合
npm install @sap/hana-client
npm install hdb-pool
Neptuneソフトウェアのスポンサーシップによって可能になったSAP HANAサポート。
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
mongodb (実験)の場合
npm install mongodb@^5.2.0 --save
NativeScript 、 React-Native 、およびCordovaの場合
サポートされているプラットフォームのドキュメントを確認してください
使用するデータベースに応じて、そのうちの1つのみをインストールします。
また、TypeScriptバージョン4.5以降を使用していることを確認してくださいtsconfig.json
で次の設定を有効にしています。
"emitDecoratorMetadata" : true ,
"experimentalDecorators" : true ,
また、コンパイラオプションのlib
セクションでes6
有効にするか、 @types
からes6-shim
をインストールする必要があります。
Typeormを始める最も簡単な方法は、CLIコマンドを使用してスタータープロジェクトを生成することです。 nodejsアプリケーションでTypeormを使用している場合にのみ、クイックスタートが機能します。他のプラットフォームを使用している場合は、ステップバイステップガイドに進みます。
CLIを使用して新しいプロジェクトを作成するには、次のコマンドを実行します。
npx typeorm init --name MyProject --database postgres
ここで、 name
はプロジェクトの名前とdatabase
が使用するデータベースです。データベースは、 mysql
、 mariadb
、 postgres
、 cockroachdb
、 sqlite
、 mssql
、 sap
、 spanner
、 oracle
、 mongodb
、 cordova
、 react-native
、 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
実行することにより、Expressがインストールされてさらに高度なプロジェクトを生成できます。
npx typeorm init --name MyProject --database postgres --docker
実行することにより、docker-composeファイルを生成できます。
ORMに何を期待していますか?まず第一に、あなたのためにデータベーステーブルを作成し、ほとんど保守可能なSQLクエリを書く必要なくデータを見つけ /挿入 /削除 /削除することを期待しています。このガイドでは、Typeormをゼロからセットアップし、ORMに期待していることを実行する方法を示します。
データベースの使用は、テーブルの作成から始まります。 Typeormにデータベーステーブルを作成するようにどのように指示しますか?答えは - モデルを通してです。アプリのモデルはデータベーステーブルです。
たとえば、 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
デコレータを使用して列に作成するエンティティのプロパティを飾るだけです。
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
デコレーター。
列のあるデータベーステーブルを生成しましたが、残っていることが1つあります。各データベーステーブルには、プライマリキーのある列が必要です。
各エンティティには、少なくとも1つの主要なキー列が必要です。これは要件であり、避けることはできません。列をプライマリキーにするには、 @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列を自動生成したいとしましょう(これは自動インクレメント /シーケンス /シリアル /生成されたID列として知られています)。そのためには、 @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
}
列タイプはデータベース固有です。データベースのサポートを任意の列タイプを設定できます。サポートされている列タイプの詳細については、こちらをご覧ください。
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
、 mssql
、 oracle
、 sap
、 spanner
、 cordova
、 nativescript
、 react-native
、 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の詳細については、こちらをご覧ください。
次に、 EntityManager
代わりにコードをリファクタリングし、 Repository
を使用しましょう。各エンティティには、すべての操作をエンティティで処理する独自のリポジトリがあります。エンティティを大いに処理する場合、リポジトリは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 )
次に、データベースから1枚の写真をロードして、更新して保存しましょう。
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
の写真がデータベースから削除されます。
別のクラスと1対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
という新しいデコレーターを使用しています。これにより、2つのエンティティ間に1対1の関係を作成できます。 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" ,
)
関係は、一方向または双方向になる可能性があります。現在、くますと写真の関係は一方向です。関係の所有者は顕微鏡であり、写真はくましていることについては何も知りません。これにより、フォトサイドから顕微鏡にアクセスすることが複雑になります。この問題を修正するには、逆の関係を追加し、くましと写真の双方向との関係を作る必要があります。エンティティを変更しましょう。
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
関係の逆側の名前を返す関数です。ここでは、写真クラスのメタデータプロパティが写真クラスに顕微鏡を保存する場所であることを示します。写真のプロパティを返す関数を渡す代わりに、 "metadata"
のような@OneToOne
デコレーターに文字列を単純に渡すことができます。しかし、この機能型アプローチを使用して、リファクタリングを容易にしました。
関係の片側にのみ@JoinColumn
デコレーターを使用する必要があることに注意してください。このデコレーターをかけた側面は、関係の所有側になります。関係の所有側には、データベースに外部キーを含む列が含まれています。
TypeScriptプロジェクトで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 >
}
次に、写真とその写真メタデータを1回のクエリにロードしましょう。それを行うには2つの方法があります - 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 ,
} ,
} )
ここでは、写真にはデータベースからの写真の配列が含まれ、各写真には写真メタデータが含まれます。このドキュメントの検索オプションの詳細をご覧ください。
検索オプションを使用することは優れており、Dead Simpleですが、より複雑なクエリが必要な場合は、代わりに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." )
以前のように、メタデータのphoto
プロパティの代わりに、写真のmetadata
プロパティを設定したことに注意してください。 cascade
機能は、写真を写真の側面からメタデータに接続する場合にのみ機能します。メタデータ側を設定した場合、メタデータは自動的に保存されません。
多くの/1対1〜多くの関係を作成しましょう。写真には1人の著者がいて、各著者が多くの写真を撮ることができます。まず、 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
}
多くのもの / 1対1と多くの関係では、オーナー側は常に多くの関係です。これは、 @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はアルバム_Photos_Photo_Albumsジャンクションテーブルを作成します。
+-------------+--------------+----------------------------+
| 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 ( )
このクエリは、公開されたすべての写真を「私の」または「ミシュカ」名で選択します。位置5(ページネーションオフセット)の結果を選択し、10の結果(ページネーション制限)のみを選択します。選択結果は、IDによって降順で注文されます。フォトアルバムは結合され、メタデータは内側に参加します。
アプリケーションでクエリビルダーをよく使用します。 QueryBuilderの詳細については、こちらをご覧ください。
使用法の例については、サンプルのサンプルをご覧ください。
クローンで始めることができるいくつかのリポジトリがあります。
Typeormの作業を簡素化し、他のモジュールと統合するいくつかの拡張機能があります。
data-source.ts
自動的に更新します-Typeorm-CodeBase-Syncrelations
の簡単な操作 - タイプの関係relations
自動的に生成 - typeorm-relations-graphql ここで貢献について学び、ここで開発環境をセットアップする方法を学びます。
このプロジェクトは、貢献するすべての人々のおかげで存在します。
オープンソースは難しく、時間がかかります。 Typeormの将来に投資したい場合は、スポンサーになり、コアチームがTypeormの改善と新機能により多くの時間を費やすことができます。スポンサーになります
ゴールドスポンサーになり、コア貢献者からプレミアムテクニカルサポートを取得します。ゴールドスポンサーになります