欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

NestJS中集成TypeORM進(jìn)行數(shù)據(jù)庫(kù)操作

 更新時(shí)間:2024年12月28日 11:03:54   作者:乘風(fēng)遠(yuǎn)洋  
本文深入探討了如何在NestJS中集成TypeORM進(jìn)行數(shù)據(jù)庫(kù)操作,包括TypeORM的配置和集成、實(shí)體設(shè)計(jì)和關(guān)系映射、Repository模式的應(yīng)用、事務(wù)處理方案、數(shù)據(jù)庫(kù)遷移管理、性能優(yōu)化策略

本文深入探討了如何在NestJS中集成TypeORM進(jìn)行數(shù)據(jù)庫(kù)操作,包括TypeORM的配置和集成、實(shí)體設(shè)計(jì)和關(guān)系映射、Repository模式的應(yīng)用、事務(wù)處理方案、數(shù)據(jù)庫(kù)遷移管理、性能優(yōu)化策略。

TypeORM 集成配置

1. 安裝依賴

首先安裝必要的依賴包:

npm install @nestjs/typeorm typeorm pg
# 如果使用 MySQL
# npm install @nestjs/typeorm typeorm mysql2

2. 數(shù)據(jù)庫(kù)配置

// src/config/database.config.ts
import { TypeOrmModuleOptions } from '@nestjs/typeorm';

export const databaseConfig: TypeOrmModuleOptions = {
  type: 'postgres',
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT) || 5432,
  username: process.env.DB_USERNAME || 'postgres',
  password: process.env.DB_PASSWORD || 'postgres',
  database: process.env.DB_DATABASE || 'nestjs_db',
  entities: ['dist/**/*.entity{.ts,.js}'],
  synchronize: process.env.NODE_ENV !== 'production',
  logging: process.env.NODE_ENV !== 'production',
  ssl: process.env.DB_SSL === 'true',
};

// src/app.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { databaseConfig } from './config/database.config';

@Module({
  imports: [
    TypeOrmModule.forRoot(databaseConfig),
    // 其他模塊
  ],
})
export class AppModule {}

實(shí)體設(shè)計(jì)與關(guān)系映射

1. 基礎(chǔ)實(shí)體設(shè)計(jì)

// src/entities/base.entity.ts
import { 
  PrimaryGeneratedColumn, 
  CreateDateColumn, 
  UpdateDateColumn,
  DeleteDateColumn 
} from 'typeorm';

export abstract class BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date;
}

// src/users/entities/user.entity.ts
import { Entity, Column, OneToMany } from 'typeorm';
import { BaseEntity } from '../entities/base.entity';
import { Post } from './post.entity';

@Entity('users')
export class User extends BaseEntity {
  @Column({ length: 100 })
  name: string;

  @Column({ unique: true })
  email: string;

  @Column({ select: false })
  password: string;

  @OneToMany(() => Post, post => post.author)
  posts: Post[];
}

// src/posts/entities/post.entity.ts
import { Entity, Column, ManyToOne, JoinColumn } from 'typeorm';
import { BaseEntity } from '../entities/base.entity';
import { User } from './user.entity';

@Entity('posts')
export class Post extends BaseEntity {
  @Column()
  title: string;

  @Column('text')
  content: string;

  @Column({ default: false })
  published: boolean;

  @ManyToOne(() => User, user => user.posts)
  @JoinColumn({ name: 'author_id' })
  author: User;
}

2. 關(guān)系映射策略

// src/users/entities/profile.entity.ts
import { Entity, Column, OneToOne, JoinColumn } from 'typeorm';
import { BaseEntity } from '../entities/base.entity';
import { User } from './user.entity';

@Entity('profiles')
export class Profile extends BaseEntity {
  @Column()
  avatar: string;

  @Column('text')
  bio: string;

  @OneToOne(() => User)
  @JoinColumn({ name: 'user_id' })
  user: User;
}

// src/posts/entities/tag.entity.ts
import { Entity, Column, ManyToMany } from 'typeorm';
import { BaseEntity } from '../entities/base.entity';
import { Post } from './post.entity';

@Entity('tags')
export class Tag extends BaseEntity {
  @Column({ unique: true })
  name: string;

  @ManyToMany(() => Post, post => post.tags)
  posts: Post[];
}

// 更新 Post 實(shí)體,添加標(biāo)簽關(guān)系
@Entity('posts')
export class Post extends BaseEntity {
  // ... 其他字段

  @ManyToMany(() => Tag, tag => tag.posts)
  @JoinTable({
    name: 'posts_tags',
    joinColumn: { name: 'post_id' },
    inverseJoinColumn: { name: 'tag_id' }
  })
  tags: Tag[];
}

數(shù)據(jù)庫(kù)操作實(shí)現(xiàn)

1. Repository 模式

// src/users/users.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { CreateUserDto, UpdateUserDto } from './dto';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>
  ) {}

  async create(createUserDto: CreateUserDto): Promise<User> {
    const user = this.usersRepository.create(createUserDto);
    return await this.usersRepository.save(user);
  }

  async findAll(): Promise<User[]> {
    return await this.usersRepository.find({
      relations: ['posts', 'profile']
    });
  }

  async findOne(id: string): Promise<User> {
    const user = await this.usersRepository.findOne({
      where: { id },
      relations: ['posts', 'profile']
    });

    if (!user) {
      throw new NotFoundException(`User with ID ${id} not found`);
    }

    return user;
  }

  async update(id: string, updateUserDto: UpdateUserDto): Promise<User> {
    const user = await this.findOne(id);
    Object.assign(user, updateUserDto);
    return await this.usersRepository.save(user);
  }

  async remove(id: string): Promise<void> {
    const user = await this.findOne(id);
    await this.usersRepository.softRemove(user);
  }
}

2. 查詢構(gòu)建器

// src/posts/posts.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Post } from './entities/post.entity';

@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Post)
    private postsRepository: Repository<Post>
  ) {}

  async findPublishedPosts() {
    return await this.postsRepository
      .createQueryBuilder('post')
      .leftJoinAndSelect('post.author', 'author')
      .leftJoinAndSelect('post.tags', 'tags')
      .where('post.published = :published', { published: true })
      .orderBy('post.createdAt', 'DESC')
      .getMany();
  }

  async searchPosts(query: string) {
    return await this.postsRepository
      .createQueryBuilder('post')
      .leftJoinAndSelect('post.author', 'author')
      .where('post.title ILIKE :query OR post.content ILIKE :query', {
        query: `%${query}%`
      })
      .orderBy('post.createdAt', 'DESC')
      .getMany();
  }

  async getPostStats() {
    return await this.postsRepository
      .createQueryBuilder('post')
      .select('author.name', 'authorName')
      .addSelect('COUNT(*)', 'postCount')
      .leftJoin('post.author', 'author')
      .groupBy('author.name')
      .getRawMany();
  }
}

事務(wù)處理

1. 事務(wù)裝飾器

// src/common/decorators/transaction.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { getManager } from 'typeorm';

export const Transaction = createParamDecorator(
  async (data: unknown, ctx: ExecutionContext) => {
    const queryRunner = getManager().connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    return queryRunner;
  }
);

// 使用示例
@Post('transfer')
async transfer(
  @Transaction() queryRunner,
  @Body() transferDto: TransferDto
) {
  try {
    // 執(zhí)行轉(zhuǎn)賬操作
    await queryRunner.manager.update(Account, 
      transferDto.fromId, 
      { balance: () => `balance - ${transferDto.amount}` }
    );

    await queryRunner.manager.update(Account, 
      transferDto.toId, 
      { balance: () => `balance + ${transferDto.amount}` }
    );

    await queryRunner.commitTransaction();
  } catch (err) {
    await queryRunner.rollbackTransaction();
    throw err;
  } finally {
    await queryRunner.release();
  }
}

2. 事務(wù)管理器

// src/common/services/transaction.service.ts
import { Injectable } from '@nestjs/common';
import { Connection, QueryRunner } from 'typeorm';

@Injectable()
export class TransactionService {
  constructor(private connection: Connection) {}

  async executeInTransaction<T>(
    callback: (queryRunner: QueryRunner) => Promise<T>
  ): Promise<T> {
    const queryRunner = this.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      const result = await callback(queryRunner);
      await queryRunner.commitTransaction();
      return result;
    } catch (err) {
      await queryRunner.rollbackTransaction();
      throw err;
    } finally {
      await queryRunner.release();
    }
  }
}

// 使用示例
@Injectable()
export class PaymentService {
  constructor(
    private transactionService: TransactionService,
    private ordersService: OrdersService
  ) {}

  async processPayment(paymentDto: PaymentDto) {
    return await this.transactionService.executeInTransaction(async queryRunner => {
      const order = await this.ordersService.findOne(paymentDto.orderId);
      
      // 更新訂單狀態(tài)
      await queryRunner.manager.update(Order, order.id, {
        status: 'paid'
      });

      // 創(chuàng)建支付記錄
      const payment = queryRunner.manager.create(Payment, {
        order,
        amount: paymentDto.amount
      });
      await queryRunner.manager.save(payment);

      return payment;
    });
  }
}

數(shù)據(jù)庫(kù)遷移

1. 遷移配置

// ormconfig.js
module.exports = {
  type: 'postgres',
  host: process.env.DB_HOST,
  port: parseInt(process.env.DB_PORT),
  username: process.env.DB_USERNAME,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_DATABASE,
  entities: ['dist/**/*.entity{.ts,.js}'],
  migrations: ['dist/migrations/*{.ts,.js}'],
  cli: {
    migrationsDir: 'src/migrations'
  }
};

// package.json
{
  "scripts": {
    "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js",
    "migration:create": "npm run typeorm migration:create -- -n",
    "migration:generate": "npm run typeorm migration:generate -- -n",
    "migration:run": "npm run typeorm migration:run",
    "migration:revert": "npm run typeorm migration:revert"
  }
}

2. 遷移示例

// src/migrations/1642340914321-CreateUsersTable.ts
import { MigrationInterface, QueryRunner, Table } from 'typeorm';

export class CreateUsersTable1642340914321 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.createTable(
      new Table({
        name: 'users',
        columns: [
          {
            name: 'id',
            type: 'uuid',
            isPrimary: true,
            generationStrategy: 'uuid',
            default: 'uuid_generate_v4()'
          },
          {
            name: 'name',
            type: 'varchar',
            length: '100'
          },
          {
            name: 'email',
            type: 'varchar',
            isUnique: true
          },
          {
            name: 'password',
            type: 'varchar'
          },
          {
            name: 'created_at',
            type: 'timestamp',
            default: 'now()'
          },
          {
            name: 'updated_at',
            type: 'timestamp',
            default: 'now()'
          },
          {
            name: 'deleted_at',
            type: 'timestamp',
            isNullable: true
          }
        ]
      })
    );
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.dropTable('users');
  }
}

性能優(yōu)化

1. 查詢優(yōu)化

// src/posts/posts.service.ts
@Injectable()
export class PostsService {
  constructor(
    @InjectRepository(Post)
    private postsRepository: Repository<Post>
  ) {}

  // 使用分頁(yè)和緩存
  async findAll(page = 1, limit = 10) {
    const [posts, total] = await this.postsRepository.findAndCount({
      relations: ['author', 'tags'],
      skip: (page - 1) * limit,
      take: limit,
      cache: {
        id: `posts_page_${page}`,
        milliseconds: 60000 // 1分鐘緩存
      }
    });

    return {
      data: posts,
      meta: {
        total,
        page,
        lastPage: Math.ceil(total / limit)
      }
    };
  }

  // 使用子查詢優(yōu)化
  async findPopularPosts() {
    return await this.postsRepository
      .createQueryBuilder('post')
      .leftJoinAndSelect('post.author', 'author')
      .addSelect(subQuery => {
        return subQuery
          .select('COUNT(*)', 'commentCount')
          .from('comments', 'comment')
          .where('comment.postId = post.id');
      }, 'commentCount')
      .orderBy('commentCount', 'DESC')
      .limit(10)
      .getMany();
  }
}

2. 索引優(yōu)化

// src/posts/entities/post.entity.ts
@Entity('posts')
@Index(['title', 'content']) // 復(fù)合索引
export class Post extends BaseEntity {
  @Column()
  @Index() // 單列索引
  title: string;

  @Column('text')
  content: string;

  @Column()
  @Index()
  authorId: string;

  // ... 其他字段
}

寫(xiě)在最后

本文詳細(xì)介紹了 NestJS 中的數(shù)據(jù)庫(kù)操作實(shí)踐:

  1. TypeORM 的配置和集成
  2. 實(shí)體設(shè)計(jì)和關(guān)系映射
  3. Repository 模式的應(yīng)用
  4. 事務(wù)處理方案
  5. 數(shù)據(jù)庫(kù)遷移管理
  6. 性能優(yōu)化策略

到此這篇關(guān)于NestJS中集成TypeORM進(jìn)行數(shù)據(jù)庫(kù)操作的文章就介紹到這了,更多相關(guān)NestJS集成TypeORM數(shù)據(jù)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于npm?i幾種常見(jiàn)命令的區(qū)別詳解

    關(guān)于npm?i幾種常見(jiàn)命令的區(qū)別詳解

    npm(Node.js Package Manager)是一個(gè)Node.js的包管理工具,用來(lái)解決Node.js代碼部署問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于npm?i幾種常見(jiàn)命令的那點(diǎn)事,需要的朋友可以參考下
    2023-03-03
  • Node.js 深度調(diào)試方法解析

    Node.js 深度調(diào)試方法解析

    這篇文章主要介紹了Node.js 深度調(diào)試方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • node操作mysql數(shù)據(jù)庫(kù)實(shí)例詳解

    node操作mysql數(shù)據(jù)庫(kù)實(shí)例詳解

    這篇文章主要介紹了node操作mysql數(shù)據(jù)庫(kù),結(jié)合實(shí)例形式較為詳細(xì)的分析了node操作數(shù)據(jù)庫(kù)的連接、增刪改查、事務(wù)處理及錯(cuò)誤處理相關(guān)操作技巧,需要的朋友可以參考下
    2017-03-03
  • Node.js安裝教程和NPM包管理器使用詳解

    Node.js安裝教程和NPM包管理器使用詳解

    這篇文章主要介紹了Node.js安裝教程和NPM包管理器使用詳解,安裝部分講解了Windows、和MAC OS下的安裝圖解,并介紹了Linux下的源碼安裝方法,最后對(duì)NPM包管理器做了詳細(xì)介紹,需要的朋友可以參考下
    2014-08-08
  • node.js下when.js 的異步編程實(shí)踐

    node.js下when.js 的異步編程實(shí)踐

    這篇文章主要介紹了node.js下when.js 的異步編程實(shí)踐,需要的朋友可以參考下
    2014-12-12
  • 前端包管理器npm、Yarn和pnpm的超全面比較

    前端包管理器npm、Yarn和pnpm的超全面比較

    NPM(Node Package Manager)是Node.js默認(rèn)的包管理器,這篇文章主要給大家介紹了關(guān)于前端包管理器npm、Yarn和pnpm的超全面比較,文中介紹的非常詳細(xì),需要的朋友可以參考下
    2024-09-09
  • 如何用node優(yōu)雅地打印全鏈路日志

    如何用node優(yōu)雅地打印全鏈路日志

    這篇文章主要給大家介紹了關(guān)于如何用node優(yōu)雅地打印全鏈路日志的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Windows系統(tǒng)下Node.js安裝以及環(huán)境配置的完美教程

    Windows系統(tǒng)下Node.js安裝以及環(huán)境配置的完美教程

    相信對(duì)于很多關(guān)注javascript發(fā)展的同學(xué)來(lái)說(shuō),nodejs已經(jīng)不是一個(gè)陌生的詞眼,下面這篇文章主要給大家介紹了關(guān)于Windows系統(tǒng)下Node.js安裝以及環(huán)境配置的完美教程,需要的朋友可以參考下
    2022-06-06
  • 淺談Node.js:fs文件系統(tǒng)模塊

    淺談Node.js:fs文件系統(tǒng)模塊

    本篇文章主要介紹了Node.js:fs文件系統(tǒng)模塊,具有一定的參考價(jià)值,有需要的可以了解一下。
    2016-12-12
  • 總結(jié)幾道關(guān)于Node.js的面試問(wèn)題

    總結(jié)幾道關(guān)于Node.js的面試問(wèn)題

    這篇文章主要總結(jié)了幾道關(guān)于Node.js的面試問(wèn)題,通過(guò)這些問(wèn)題就來(lái)判斷一個(gè)人的Node.js水平是不太嚴(yán)謹(jǐn)?shù)?,但是它能讓你?duì)面試者在Node.js上的經(jīng)驗(yàn)如何有個(gè)大概的了解。有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-01-01

最新評(píng)論