6.13-bob: ORM — TypeORM (entity, repository, relations)
6-QISM — Ma'lumotlar bazasi (Database) · 13-mavzu
1. Kirish va motivatsiya
Sequelize (klassik — 6.11) va Prisma (schema-first — 6.12) ni bildik. Endi uchinchi va oxirgi ORM — TypeORM ni o'rganamiz. TypeORM — yana boshqacha yondashuv: class va dekorator (decorator) asosida. Model — oddiy TypeScript class, dekoratorlar (@Entity, @Column) bilan bezatilgan. Bu — TypeScript bilan tabiiy, va eng muhimi: NestJS (8-QISM) bilan eng yaxshi ishlaydi (NestJS o'zi ham dekorator asosida). Sizning stack'ingda TypeORM bor, va NestJS qismiga (8) bu bob bevosita tayyorgarlik.
TypeORM — "TypeScript ORM" (nomidan ham). U class'larni jadvalga, obyektlarni qatorga moslaydi, lekin dekorator bilan (Prisma'ning alohida schema fayli yoki Sequelize'ning define o'rniga). Masalan, @Entity() class — jadval, @Column() xususiyat — ustun, @OneToMany() — bog'lanish. Bu — kod va model bir joyda (class ichida), TypeScript turlari bilan integratsiyalashgan.
TypeORM ikki asosiy ish uslubini beradi: Active Record (model'ning o'zida metodlar — user.save()) va Data Mapper (alohida repository — userRepository.save(user)). Data Mapper (repository pattern) — kattaroq loyihalar uchun afzal (toza arxitektura — 9), va NestJS standartda shuni qo'llaydi. Bu bob: entity, repository pattern, relations, query builder, va tranzaksiya — chuqur. NestJS'ga (8) o'tishdan oldin oxirgi DB bobi.
O'xshatish: Prisma — alohida arxitektura chizmasi (schema.prisma — bino loyihasi alohida qog'ozda). TypeORM — bino qismlariga yorliq yopishtirish (class'ning o'ziga
@Entity,@Columndekoratorlari — "bu jadval", "bu ustun" deb belgilash). Ikkalasi ham bino quradi, lekin TypeORM — model va belgilar bir joyda (class ichida), kod bilan integratsiya.
Nega muhim?
- NestJS bilan tabiiy — NestJS (8) dekorator asosida; TypeORM mos (8.3 tayyorgarligi).
- TypeScript — class/dekorator, tur integratsiyasi.
- Repository pattern — toza arxitektura (9: Clean Architecture).
- Stack talabi — TypeORM sizning stack'ingda; uchchala ORM'ni bilish.
2. Nazariya — chuqur tushuntirish
2.1. TypeORM nima va dekorator yondashuvi
TypeORM — TypeScript/JavaScript uchun ORM, dekorator asosida (typeorm.io):
Class (TS) + dekorator jadval
@Entity() jadval (User class "user" jadval)
@Column() ustun
@PrimaryGeneratedColumn() PK (avto)
@OneToMany() / @ManyToOne() bog'lanish
Model = TypeScript class (turlar bilan); belgilar = dekoratorDekorator (7.6: TS decorators) — class/xususiyatga "yorliq" qo'shuvchi maxsus sintaksis (
@). TypeORM ularni o'qib, jadval/ustun/bog'lanishni biladi. Prisma'dan farq: alohida schema fayl yo'q — hammasi class ichida (kod bilan birga).
2.2. Active Record vs Data Mapper
TypeORM ikki ish uslubini beradi (typeorm.io):
Active Record — model O'ZIDA metodlar:
const user = new User(); user.ism = "Ali"; await user.save();
await User.findOne({ where: { id: 1 } });
sodda, kichik loyiha; lekin model + DB mantig'i aralash
Data Mapper — alohida REPOSITORY:
await userRepository.save(user);
await userRepository.findOne({ where: { id: 1 } });
toza ajratish (model = ma'lumot; repository = DB amali); KATTA loyiha, NestJSTanlov (typeorm/libeo): Data Mapper (repository) — afzal (toza arxitektura — 9, test oson, NestJS standarti — 8.3). Active Record — kichik/tez loyiha. Bu bobda asosan Data Mapper (repository pattern).
2.3. O'rnatish va DataSource
npm install typeorm reflect-metadata # ORM + dekorator metama'lumot
npm install pg # driver (yoki mysql2)import "reflect-metadata"; // ENG TEPADA (dekorator uchun shart)
import { DataSource } from "typeorm";
export const AppDataSource = new DataSource({
type: "postgres", // DB turi
url: process.env.DATABASE_URL, // (5.8)
entities: [User, Order], // model class'lar
synchronize: false, // production'da FALSE (2.13)
logging: true, // SQL log (dev)
});
await AppDataSource.initialize(); // ulanish
reflect-metadataeng tepada import qilinishi shart (dekoratorlar metama'lumot uchun). DataSource — ulanish + sozlama (Prisma client / Sequelize instance ekvivalenti).synchronize— schema'ni avtomatik moslash (dev'da mumkin, production'da XAVFLI — 2.13).
2.4. Entity (jadval) — dekorator bilan
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm";
@Entity("users") // jadval nomi
export class User {
@PrimaryGeneratedColumn() // PK, avto (6.4: SERIAL)
id: number;
@Column({ length: 50 }) // VARCHAR(50)
ism: string;
@Column({ unique: true }) // UNIQUE
email: string;
@Column({ select: false }) // default'da qaytarilmaydi (parol — 14)
parol: string;
@Column({ type: "enum", enum: ["user", "admin"], default: "user" })
rol: string;
@CreateDateColumn() // createdAt avtomatik
createdAt: Date;
@UpdateDateColumn() // updatedAt avtomatik (6.2)
updatedAt: Date;
}Entity dekoratorlari:
@Entity(jadval),@PrimaryGeneratedColumn(PK),@Column(ustun + sozlama),@CreateDateColumn/@UpdateDateColumn(avtomatik vaqt). Class — oddiy TS (turlar bilan); dekorator — DB metama'lumoti. Toza, o'qiladigan.
2.5. Column turlari va sozlamalari
@Column({ type: "varchar", length: 100 }) // VARCHAR
@Column({ type: "decimal", precision: 10, scale: 2 }) // DECIMAL (pul — 6.4: 2.3)
@Column({ type: "text", nullable: true }) // ixtiyoriy
@Column({ type: "boolean", default: true })
@Column({ type: "jsonb", nullable: true }) // JSONB (6.6: 2.10)
@Column("simple-array") // massiv
@Column({ type: "timestamptz" })
@Columnsozlamalari:type(DB tur),length,nullable,default,unique,select.precision/scale(DECIMAL — pul). TypeScript turi (string,number) + DB turi (type) — ikkalasi.
2.6. Repository (DB amallari)
Repository — entity bilan ishlash (CRUD — Data Mapper — 2.2):
const userRepo = AppDataSource.getRepository(User);
// CREATE
const user = userRepo.create({ ism: "Ali", email: "ali@a.uz" }); // obyekt yaratadi (saqlamaydi)
await userRepo.save(user); // saqlaydi (INSERT/UPDATE)
// READ
await userRepo.find(); // hammasi
await userRepo.findOne({ where: { id: 1 } }); // bittasi
await userRepo.findOneBy({ email: "ali@a.uz" }); // qisqa
await userRepo.find({ where: { yosh: MoreThan(18) } }); // operator (2.8)
// UPDATE
await userRepo.update({ id: 1 }, { yosh: 26 }); // to'g'ridan
// yoki: user.yosh = 26; await userRepo.save(user);
// DELETE
await userRepo.delete({ id: 1 });
await userRepo.softDelete({ id: 1 }); // soft delete (@DeleteDateColumn bilan)
getRepository(Entity)— repository oladi.create(obyekt — saqlamaydi) +save(saqlaydi), yokiinsert.find/findOne/findOneBy.update/delete/softDelete. Repository — barcha DB amali shu yerda (toza — 9).
2.7. Custom repository (toza arxitektura — 9)
Murakkab so'rovlar uchun custom repository (repository pattern — medium/anton):
// Repository'ni kengaytirib, maxsus metodlar (9: Clean Architecture)
export const UserRepository = AppDataSource.getRepository(User).extend({
findFaollar() {
return this.find({ where: { faol: true } });
},
findEmailBilan(email) {
return this.createQueryBuilder("u") // query builder (2.9)
.addSelect("u.parol") // parolni ham (login uchun)
.where("u.email = :email", { email })
.getOne();
},
});Custom repository — entity'ga oid barcha so'rov mantiqini bir joyda (libeo). Biznes logika (service — 5.6) repository'ni ishlatadi (DB tafsilotini bilmaydi — 9: separation of concerns). NestJS'da bu —
@InjectRepository8.3-bob.
2.8. Operatorlar (Find Options)
import { MoreThan, LessThan, Like, In, Between, IsNull, Not } from "typeorm";
await userRepo.find({
where: {
yosh: MoreThan(18), // > 18
rol: In(["admin", "moderator"]), // IN
ism: Like("Al%"), // LIKE
email: Not(IsNull()), // NOT NULL
},
order: { yosh: "DESC" }, // ORDER BY (6.4)
take: 10, skip: 20, // limit, offset
select: ["id", "ism", "email"], // SELECT ustunlar
relations: { orders: true }, // eager (JOIN — 2.10)
});Find operatorlari:
MoreThan/LessThan,Like,In,Between,IsNull,Not(funksiya sifatida — 6.4: 2.9).take/skip(sahifalash),order,select,relations(bog'lanish). Sequelize Op 6.11-bob / Prisma 6.12-bob ekvivalenti.
2.9. Query Builder (murakkab so'rov)
Murakkab so'rov uchun Query Builder (raw SQL'dan oldin — typeorm):
const natija = await userRepo
.createQueryBuilder("u") // alias "u"
.leftJoinAndSelect("u.orders", "o") // JOIN (6.7)
.where("u.yosh > :yosh", { yosh: 18 }) // parametrli (14)
.andWhere("o.holat = :holat", { holat: "tugallandi" })
.orderBy("u.createdAt", "DESC")
.take(10)
.getMany();Query Builder — find options yetmaganda (JOIN, murakkab shart, agregat — 6.7). Parametrli (
:yosh— injection himoyasi — 14). Raw SQL'ga o'tishdan oldingi qatlam (window/CTE uchun — baribir raw kerak bo'lishi mumkin — 2.14). Kuchli, lekin SQL bilim talab.
2.10. Relations (bog'lanishlar)
// One-to-Many: User Order (6.1: 2.5)
@Entity()
export class User {
@PrimaryGeneratedColumn() id: number;
@OneToMany(() => Order, (order) => order.user) // bir user — ko'p order
orders: Order[];
}
@Entity()
export class Order {
@PrimaryGeneratedColumn() id: number;
@ManyToOne(() => User, (user) => user.orders) // ko'p order — bir user
@JoinColumn({ name: "user_id" }) // FK ustun nomi
user: User;
}// Many-to-Many: @ManyToMany + @JoinTable (owning side)
@ManyToMany(() => Tag)
@JoinTable() // junction jadval (owning side)
tags: Tag[];Relation dekoratorlari (typeorm):
@OneToOne,@OneToMany/@ManyToOne(juft),@ManyToMany.@JoinColumn— FK egasini belgilaydi (one-to-one/many-to-one);@JoinTable— many-to-many junction (faqat bir tomonda — owning side). Bog'lanish ikki tomonda ta'riflanadi.
2.11. Eager va lazy loading
// Eager (relations bilan — JOIN — 2.8)
await userRepo.find({ relations: { orders: true } }); // buyurtmalar birga
// Yoki entity'da default eager (ehtiyot — har doim yuklanadi)
@OneToMany(() => Order, o => o.user, { eager: true })
// Lazy (kerak bo'lganda — Promise)
@OneToMany(() => Order, o => o.user, { lazy: true })
orders: Promise<Order[]>;Eager (
relations— N+1 oldini oladi — 6.10: 2.11) — kerakli joyda. Entity'daeager: true— har doim yuklanadi (ehtiyot — ortiqcha). Lazy —await user.orders(kerak bo'lganda). Repository'darelations— eng moslashuvchan (so'rovga qarab).
2.12. Tranzaksiya (QueryRunner / transaction)
// 1. DataSource.transaction (sodda — managed)
await AppDataSource.transaction(async (manager) => {
await manager.update(Account, { id: 1 }, { balans: () => "balans - 100" });
await manager.update(Account, { id: 2 }, { balans: () => "balans + 100" });
// xato avtomatik rollback (6.9)
});
// 2. QueryRunner (to'liq nazorat)
const queryRunner = AppDataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.manager.save(order);
await queryRunner.commitTransaction();
} catch (err) {
await queryRunner.rollbackTransaction();
} finally {
await queryRunner.release(); // (6.5: 2.10)
}Tranzaksiya — ikki usul:
AppDataSource.transaction(async manager)(managed — sodda, afzal);QueryRunner(to'liq nazorat — lock, izolyatsiya — 6.9).manager— tranzaksiya ichidagi entity manager. NestJS'da DataSource inject qilinadi 8.3-bob.
2.13. synchronize va migration (muhim)
TypeORM synchronize: true — schema'ni avtomatik moslaydi (dev'da qulay, production'da XAVFLI):
synchronize: true entity o'zgarsa, DB AVTOMATIK moslanadi
production'da: ma'lumot YO'QOLISHI mumkin (ustun o'chsa — data o'chadi!)
dev'da: tez (lekin migration o'rganish yaxshiroq)
Production: synchronize: false + MIGRATION (nazorat ostida — 6.14)Production'da
synchronize: false(typeorm, eng muhim ogohlantirish):true— entity o'zgarishini DB'ga avtomatik qo'llaydi, lekin nazoratsiz (ustun o'chsa — ma'lumot yo'qoladi!). Production'da migration 6.14-bob — versiyalangan, qaytariladigan. Migration:typeorm migration:generate/migration:run.
2.14. Raw query (murakkab — 2.9 yetmaganda)
// Query builder ham yetmasa — raw (parametrli — 14)
const natija = await AppDataSource.query(
"SELECT u.ism, RANK() OVER (ORDER BY SUM(o.summa) DESC) AS reyting FROM users u ...",
[/* parametrlar */] // parametrli (injection — 14)
);Query Builder 2.9-bob ko'p narsani qiladi, lekin window/murakkab CTE 6.7-bob — ba'zan
AppDataSource.query(raw). Parametrli (injection himoyasi — 14). ORM + raw aralash — normal.
2.15. NestJS bilan (8 ko'prik)
NestJS'da TypeORM 8.3-bob:
- @nestjs/typeorm modul
- TypeOrmModule.forRoot(...) — DataSource
- TypeOrmModule.forFeature([User]) — entity'lar
- @InjectRepository(User) — repository inject (DI — 8.2)
- Entity dekoratorlari + NestJS dekoratorlari — tabiiy uyg'unlik
TypeORM + NestJS = eng mashhur kombinatsiya (dekorator + DI)TypeORM NestJS bilan eng tabiiy ishlaydi (ikkalasi dekorator + DI — 8.2). Bu bob — NestJS DB qismiga 8.3-bob bevosita tayyorgarlik. Repository pattern 2.7-bob NestJS'da inject qilinadi.
2.16. Prisma vs TypeORM (yana — tanlov)
TypeORM tanla:
NestJS loyiha (dekorator — tabiiy — 2.15)
Active Record/Data Mapper moslashuvchanlik
Mavjud TypeORM loyiha
Prisma tanla 6.12-bob:
Eng yaxshi type-safety, DX
Yangi loyiha, schema-first
Eng zamonaviy
Ikkalasi ham yaxshi; NestJS'da — ko'pincha TypeORM (an'ana) yoki Prisma (zamonaviy)2026'da NestJS'da ikkalasi ham ishlatiladi (nexumo): TypeORM (an'anaviy, dekorator) yoki Prisma (zamonaviy, type-safe). Tanlov — jamoa/loyiha. Uchchala ORM'ni bilish — har qanday loyihaga tayyorlik.
2.17. Xavfsizlik va best practices (14)
Production'da synchronize: false + migration (2.13, 14) — ENG MUHIM
Repository pattern (toza arxitektura — 2.7, 9)
Relations (eager) o'ylab — N+1 oldini oling (2.11, 6.10)
select: false maxfiy maydon (parol — 2.4, 14)
Query builder/raw parametrli (injection — 2.9, 2.14, 14)
Tranzaksiya (ko'p yozuv — managed — 2.12)
reflect-metadata eng tepada 2.3-bob
Base entity (umumiy ustunlar — DRY)3. Sintaksis — tez ma'lumotnoma
import "reflect-metadata";
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn() id: number;
@Column() ism: string;
@OneToMany(() => Order, o => o.user) orders: Order[]; // relation (2.10)
}const repo = AppDataSource.getRepository(User); // (2.6)
await repo.save(repo.create({...})); // C
await repo.findOne({ where: { id }, relations: { orders: true } }); // R (2.8, 2.11)
await repo.update({ id }, {...}); await repo.delete({ id }); // U, D
repo.createQueryBuilder("u").where("u.x = :x", { x }).getMany(); // query builder (2.9)
AppDataSource.transaction(async (m) => {...}); // tranzaksiya (2.12)4. Batafsil kod namunalari
Misol 1 — DataSource (2.3)
// data-source.ts
import "reflect-metadata"; // eng tepada (2.3)
import { DataSource } from "typeorm";
import { User } from "./entities/User.js";
import { Order } from "./entities/Order.js";
import { config } from "./config/index.js";
export const AppDataSource = new DataSource({
type: "postgres",
url: config.databaseUrl, // (5.8)
entities: [User, Order, Product],
migrations: ["dist/migrations/*.js"],
synchronize: false, // production'da FALSE (2.13, 14)
logging: config.isProd ? ["error"] : true, // dev'da SQL log
});
export async function dbUlash() {
await AppDataSource.initialize();
console.log(" TypeORM ulandi");
}Misol 2 — Entity (relations bilan — 2.4, 2.10)
// entities/User.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn, BeforeInsert } from "typeorm";
import bcrypt from "bcrypt";
import { Order } from "./Order.js";
@Entity("users")
export class User {
@PrimaryGeneratedColumn() id: number;
@Column({ length: 50 }) ism: string;
@Column({ unique: true }) email: string;
@Column({ select: false }) parol: string; // parolsiz (14, 2.4)
@Column({ type: "enum", enum: ["user", "admin"], default: "user" }) rol: string;
@OneToMany(() => Order, (order) => order.user) orders: Order[]; // (2.10)
@CreateDateColumn() createdAt: Date;
@UpdateDateColumn() updatedAt: Date;
@BeforeInsert() // hook (saqlashdan oldin — 6.2: 2.16)
async hashParol() {
this.parol = await bcrypt.hash(this.parol, 12); // (5.15)
}
}// entities/Order.ts
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from "typeorm";
import { User } from "./User.js";
@Entity("orders")
export class Order {
@PrimaryGeneratedColumn() id: number;
@Column({ type: "decimal", precision: 10, scale: 2 }) summa: number; // pul (2.5)
@ManyToOne(() => User, (user) => user.orders, { onDelete: "CASCADE" }) // (2.10, 6.6: 2.7)
@JoinColumn({ name: "user_id" }) user: User;
}Misol 3 — Custom repository (2.7)
// repositories/UserRepository.ts
import { AppDataSource } from "../data-source.js";
import { User } from "../entities/User.js";
export const UserRepository = AppDataSource.getRepository(User).extend({
// Login uchun (parol bilan — select: false ni override)
findForLogin(email: string) {
return this.createQueryBuilder("u") // query builder (2.9)
.addSelect("u.parol") // parolni ham
.where("u.email = :email", { email })
.getOne();
},
// Sahifalangan ro'yxat
royxat({ page = 1, limit = 20, qidiruv }) {
const qb = this.createQueryBuilder("u");
if (qidiruv) qb.where("u.ism ILIKE :q", { q: `%${qidiruv}%` }); // qidiruv (2.9)
return qb.orderBy("u.createdAt", "DESC")
.take(limit).skip((page - 1) * limit)
.getManyAndCount(); // [ma'lumot, jami]
},
});Misol 4 — CRUD service (repository — 2.6)
import { AppDataSource } from "../data-source.js";
import { User } from "../entities/User.js";
import { UserRepository } from "../repositories/UserRepository.js";
import { MoreThan } from "typeorm";
export const UserService = {
yarat: async (data) => {
const user = UserRepository.create(data); // obyekt (2.6)
return UserRepository.save(user); // saqlaydi (hook — Misol 2)
},
topId: (id) => UserRepository.findOne({ where: { id } }), // parolsiz (2.4)
loginUchun: (email) => UserRepository.findForLogin(email), // parol bilan (Misol 3)
royxat: (params) => UserRepository.royxat(params), // (Misol 3)
yangila: (id, data) => UserRepository.update({ id }, data),
ochir: (id) => UserRepository.softDelete({ id }), // soft delete (2.6)
};Misol 5 — Relations (eager loading — 2.11)
// Buyurtma + user + mahsulotlar (relations — 2.8, 2.11)
export const buyurtmaToliq = (id) =>
AppDataSource.getRepository(Order).findOne({
where: { id },
relations: { user: true, items: { product: true } }, // ichma-ich (JOIN)
});
// Query builder bilan (murakkab — 2.9)
export const userBuyurtmalari = (userId) =>
AppDataSource.getRepository(Order)
.createQueryBuilder("o")
.leftJoinAndSelect("o.user", "u")
.where("u.id = :userId", { userId })
.andWhere("o.holat = :holat", { holat: "tugallandi" })
.orderBy("o.createdAt", "DESC")
.getMany();Misol 6 — Tranzaksiya (managed — 2.12)
import { AppDataSource } from "../data-source.js";
// Pul o'tkazish — managed transaction (2.12, 6.9)
export async function pulOtkaz(fromId, toId, summa) {
return AppDataSource.transaction(async (manager) => { // managed (avtomatik commit/rollback)
// Atomik decrement (6.9: 2.11)
await manager.decrement(Account, { id: fromId }, "balans", summa);
const from = await manager.findOneBy(Account, { id: fromId });
if (from.balans < 0) throw new Error("Balans yetarli emas"); // rollback
await manager.increment(Account, { id: toId }, "balans", summa);
await manager.save(Transfer, { fromId, toId, summa });
});
}Misol 7 — Migration (production — 2.13)
// migrations/1700000000-CreateUsers.ts
import { MigrationInterface, QueryRunner, Table } from "typeorm";
export class CreateUsers1700000000 implements MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> { // qo'llash (2.13)
await queryRunner.createTable(new Table({
name: "users",
columns: [
{ name: "id", type: "int", isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "ism", type: "varchar", length: "50" },
{ name: "email", type: "varchar", isUnique: true },
],
}));
}
async down(queryRunner: QueryRunner): Promise<void> { // qaytarish (6.14)
await queryRunner.dropTable("users");
}
}
// CLI: typeorm migration:generate (entity'dan avtomatik); migration:run; migration:revertMisol 8 — Express controller (5.6, 5.10)
import { UserService } from "../services/userService.js";
export const userlarOl = async (req, res, next) => {
try {
const [users, jami] = await UserService.royxat(req.query); // getManyAndCount (Misol 3)
res.json({ success: true, data: users, jami }); // (5.7)
} catch (err) { next(err); }
};
export const userYarat = async (req, res, next) => {
try {
const user = await UserService.yarat(req.body);
const { parol, ...natija } = user; // parolsiz (14)
res.status(201).json({ success: true, data: natija });
} catch (err) {
if (err.code === "23505") { // PostgreSQL unique (6.6: Misol 4)
return res.status(409).json({ error: "Email band" }); // (5.10)
}
next(err);
}
};5. To'g'ri va noto'g'ri holatlar
1) Production'da synchronize: true
synchronize: true ma'lumot yo'qolishi (2.13, 14)
production: synchronize: false + migration2) reflect-metadata import qilmaslik
// dekoratorlar ishlamaydi (2.3)
import { Entity } from "typeorm";
// eng tepada
import "reflect-metadata";
import { Entity } from "typeorm";3) N+1 (relations o'rniga tsikl)
// N+1 (6.10: 2.11)
for (const u of users) u.orders = await orderRepo.find({ where: { user: { id: u.id } } });
// relations
await userRepo.find({ relations: { orders: true } });4) DB mantig'i service/controller'da aralash
controller'da to'g'ridan query (toza emas — 9)
repository pattern (DB mantig'i repository'da — 2.7)5) Query builder string birlashtirish
// injection (14, 2.9)
.where(`u.email = '${email}'`)
// parametrli
.where("u.email = :email", { email })6. Keng tarqalgan xatolar va yechimlari
Xato 1 — Cannot read 'getRepository' of undefined / dekorator ishlamaydi
Sababi: reflect-metadata yo'q, yoki tsconfig'da experimentalDecorators/emitDecoratorMetadata yo'q (2.3, 7.6). Yechimi: import qiling; tsconfig sozlang.
Xato 2 — EntityMetadataNotFound
Sababi: entity DataSource'ga qo'shilmagan 2.3-bob. Yechimi: entities: [User, ...] ro'yxatga qo'shing; initialize qiling.
Xato 3 — Production'da ma'lumot yo'qoldi
Sababi: synchronize: true 2.13-bob. Yechimi: false + migration; zaxira.
Xato 4 — Parol qaytdi
Sababi: select: false yo'q, yoki query builder addSelect 2.4-bob. Yechimi: select: false; faqat login'da addSelect.
Xato 5 — N+1 (sekin)
Sababi: lazy/tsikl 2.11-bob. Yechimi: relations (eager); query builder leftJoinAndSelect.
Xato 6 — Relation undefined
Sababi: relations so'ralmagan, yoki ikki tomonlama ta'rif yo'q 2.10-bob. Yechimi: relations: { orders: true }; @OneToMany + @ManyToOne juft.
7. Integratsiya — bu mavzu stack'ning qayerida uchraydi
- SQL (6.4-6.10): TypeORM SQL ustida; query builder/raw.
- PostgreSQL/MySQL (6.5, 6.6): TypeORM type.
- Sequelize/Prisma (6.11, 6.12): muqobil ORM'lar.
- TypeScript (7): class, dekorator 7.6-bob.
- NestJS 8.3-bob: @nestjs/typeorm, @InjectRepository — tabiiy.
- Tranzaksiya/ACID 6.9-bob: transaction/QueryRunner.
- Indeks/N+1 6.10-bob: relations, @Index.
- Migration 6.14-bob: migration:run.
- Clean architecture (9): repository pattern.
- Auth 5.15-bob: User entity, parol hook.
8. Eng yaxshi amaliyotlar (best practices)
- Production'da synchronize: false + migration (eng muhim — 2.13, 14).
- Repository pattern (Data Mapper — toza, NestJS — 2.2, 2.7, 9).
- reflect-metadata eng tepada (dekorator — 2.3).
- Relations (eager) o'ylab (N+1 oldini oling — 2.11, 6.10).
- select: false maxfiy maydon (parol; login'da addSelect — 2.4).
- Query builder/raw parametrli (injection — 2.9, 2.14, 14).
- Tranzaksiya managed (ko'p yozuv — 2.12).
- Base entity (umumiy ustunlar — DRY).
- Custom repository (murakkab so'rov bir joyda — 2.7).
- Xato kodlari (23505 409 — Misol 8, 5.10).
9. Amaliy loyiha: "TypeORM bilan Backend (repository pattern)"
TypeORM'ni professional darajada mustahkamlash (NestJS'ga tayyorgarlik).
Maqsad
TypeORM bilan repository-pattern asosli, migration-asosli backend qurish: entity, relations, query builder, tranzaksiya.
Talablar (requirements)
- DataSource: synchronize: false, migrations, logging (Misol 1, 2.3, 2.13).
- Entity'lar: User/Order/Product — dekorator, relations, hook, select:false (Misol 2, 2.4, 2.10).
- Custom repository: login (parol bilan), sahifalangan ro'yxat (Misol 3, 2.7).
- CRUD service: repository orqali; soft delete (Misol 4, 2.6).
- Relations: eager (relations) + query builder (Misol 5, 2.9, 2.11).
- Tranzaksiya: pul/buyurtma (managed — Misol 6, 2.12).
- Migration: jadval yaratish (up/down — Misol 7, 2.13).
- Express: xato kodlari (23505409 — Misol 8).
- N+1 oldini olish: relations bilan 2.11-bob.
- Repository pattern: DB mantig'i repository'da (toza — 9).
Maslahatlar (hint)
reflect-metadataeng tepada (2.3, 2-xato).- synchronize: false (production — 2.13, 1-xato).
- Repository extend (custom — 2.7).
- Relations: @OneToMany + @ManyToOne juft (2.10, 6-xato).
- Query builder parametrli (
:x— 2.9, 5-xato). - select: false + addSelect (login — 2.4, 4-xato).
"Tayyor" mezonlari (acceptance criteria)
- DataSource (synchronize: false, migration).
- Entity'lar (dekorator, relations, hook).
- Custom repository (login, ro'yxat).
- CRUD service (repository, soft delete).
- Relations (eager + query builder).
- Tranzaksiya (managed).
- Migration (up/down).
- Xato kodlari (409).
- N+1 yo'q.
- Repository pattern (toza).
Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.
10. Xulosa va keyingi bobga ko'prik
Bu bobda uchinchi ORM — TypeORM ni chuqur o'rgandik:
- TypeORM (dekorator asosida — 2.1); Active Record vs Data Mapper (repository — afzal — 2.2); DataSource 2.3-bob.
- Entity (@Entity/@Column dekorator — 2.4, 2.5); Repository (CRUD — 2.6); custom repository (toza — 2.7); operatorlar 2.8-bob; Query Builder (murakkab — 2.9).
- Relations (@OneToMany/@ManyToOne/@JoinColumn/@JoinTable — 2.10); eager/lazy 2.11-bob; tranzaksiya (managed/QueryRunner — 2.12).
- synchronize: false + migration (production — 2.13); NestJS bilan tabiiy (8.3 — 2.15); Prisma vs TypeORM 2.16-bob.
Keyingi bob — 6.14-bob: Migration va seeding strategiyalari. Uch ORM'ni bildik; har birida migration ko'rdik. Endi migration'ning strategiyalarini — production'da xavfsiz schema o'zgartirish (zero-downtime, expand-contract), rollback, seeding (boshlang'ich/test ma'lumot) — chuqur, ORM-mustaqil o'rganamiz. Bu — real production'da DB'ni boshqarishning asosi.
Foydalanilgan rasmiy/ishonchli manbalar
- typeorm.io — Entities, Relations, Repository, Query Builder, DataSource, Transactions
- TypeORM docs — Active Record vs Data Mapper; OneUptime — TypeORM with NestJS 2026
- Medium (Libeo/Anton) — TypeORM best practices, repository pattern
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!