最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)文章

  • node.js中Koa框架的具體實(shí)現(xiàn)

    node.js中Koa框架的具體實(shí)現(xiàn)

    Koa由Express團(tuán)隊(duì)打造,解決回調(diào)地獄等問(wèn)題,采用async/await和統(tǒng)一Context對(duì)象,下面就來(lái)介紹一下Koa框架的使用,感興趣的可以了解一下
    2025-08-08
  • nodejs之koa2請(qǐng)求示例(GET,POST)

    nodejs之koa2請(qǐng)求示例(GET,POST)

    本篇文章主要介紹了nodejs之koa2請(qǐng)求示例(GET,POST),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • 詳解node+express+ejs+bootstrap構(gòu)建項(xiàng)目

    詳解node+express+ejs+bootstrap構(gòu)建項(xiàng)目

    本篇文章主要介紹了詳解node+express+ejs+bootstrap構(gòu)建項(xiàng)目,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2017-09-09
  • nodejs redis 發(fā)布訂閱機(jī)制封裝實(shí)現(xiàn)方法及實(shí)例代碼

    nodejs redis 發(fā)布訂閱機(jī)制封裝實(shí)現(xiàn)方法及實(shí)例代碼

    這篇文章主要介紹了nodejs redis 發(fā)布訂閱機(jī)制封裝的相關(guān)資料,這里提供了實(shí)現(xiàn)方法,及實(shí)例代碼,具有參考價(jià)值,需要的朋友可以參考下
    2016-12-12
  • 圖解NodeJS實(shí)現(xiàn)登錄注冊(cè)功能

    圖解NodeJS實(shí)現(xiàn)登錄注冊(cè)功能

    這篇文章主要介紹了NodeJS實(shí)現(xiàn)登錄注冊(cè)功能,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • windows如何把已安裝的nodejs高版本降級(jí)為低版本(圖文教程)

    windows如何把已安裝的nodejs高版本降級(jí)為低版本(圖文教程)

    這篇文章主要介紹了windows如何把已安裝的nodejs高版本降級(jí)為低版本,本文分步驟通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • Node.js(安裝,啟動(dòng),測(cè)試)

    Node.js(安裝,啟動(dòng),測(cè)試)

    這里主要介紹基于windows平臺(tái)上最簡(jiǎn)單方便的安裝方式,啟動(dòng)以及簡(jiǎn)單測(cè)試
    2014-06-06
  • NodeJS制作爬蟲(chóng)全過(guò)程

    NodeJS制作爬蟲(chóng)全過(guò)程

    這篇文章主要介紹了NodeJS制作爬蟲(chóng)的全過(guò)程,包括項(xiàng)目建立,目標(biāo)網(wǎng)站分析、使用superagent獲取源數(shù)據(jù)、使用cheerio解析、使用eventproxy來(lái)并發(fā)抓取每個(gè)主題的內(nèi)容等方面,有需要的小伙伴參考下吧。
    2014-12-12
  • Node.js學(xué)習(xí)教程之HTTP/2服務(wù)器推送【譯】

    Node.js學(xué)習(xí)教程之HTTP/2服務(wù)器推送【譯】

    這篇文章主要給大家介紹了關(guān)于Node.js學(xué)習(xí)教程之HTTP/2服務(wù)器推送的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • 10個(gè)Node.js庫(kù)幫助你優(yōu)化代碼和簡(jiǎn)化開(kāi)發(fā)

    10個(gè)Node.js庫(kù)幫助你優(yōu)化代碼和簡(jiǎn)化開(kāi)發(fā)

    這篇文章主要介紹了10個(gè)Node.js庫(kù)幫助你優(yōu)化代碼和簡(jiǎn)化開(kāi)發(fā),其中包括處理數(shù)組、對(duì)象、字符串庫(kù)Lodash,緩存數(shù)據(jù)處理庫(kù)Node-cache,解析、操作和格式化日期和時(shí)間庫(kù)Moment.js,Redis操作庫(kù),發(fā)送電子郵件庫(kù)Nodemailer
    2023-05-05

最新評(píng)論

探索| 阜宁县| 武鸣县| 东兰县| 察雅县| 乐陵市| 鄂托克前旗| 弥勒县| 常宁市| 徐水县| 车险| 淮北市| 海原县| 桦南县| 乌鲁木齐市| 连山| 潮安县| 克东县| 虹口区| 临湘市| 年辖:市辖区| 普宁市| 周口市| 蒙山县| 旬邑县| 罗江县| 岳西县| 山阴县| 东城区| 胶南市| 霞浦县| 工布江达县| 云浮市| 右玉县| 九台市| 东海县| 永修县| 通山县| 阳谷县| 昌乐县| 泰州市|