Skip to content

什么是实体

实体是一个映射到数据库表的类。 你可以通过定义一个新类来创建一个实体,并用@Entity()来标记

ts
import {Entity,Column,PrimaryGeneratedColumn} from 'typeorm'
 
@Entity()
export class Test {
    @PrimaryGeneratedColumn()
    id:number
    
    @Column()
    name:string
 
    @Column()
    password:string
 
    @Column()
    age:number
}

主列

自动递增的主键

TS
@PrimaryGeneratedColumn()
id:number

自动递增uuid

TS
@PrimaryGeneratedColumn("uuid")
id:number

列类型

ts
@Column({type:"varchar",length:200})
password: string
 
@Column({ type: "int"})
age: number
 
@CreateDateColumn({type:"timestamp"})
create_time:Date

列选项

ts
@Column({
    type:"varchar",
    name:"ipaaa", //数据库表中的列名
    nullable:true, //在数据库中使列NULL或NOT NULL。 默认情况下,列是nullable:false
    comment:"注释",
    select:true,  //定义在进行查询时是否默认隐藏此列。 设置为false时,列数据不会显示标准查询。 默认情况下,列是select:true
    default:"xxxx", //加数据库级列的DEFAULT值
    primary:false, //将列标记为主要列。 使用方式和@ PrimaryColumn相同。
    update:true, //指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。 默认值为"true"
    collation:"", //定义列排序规则。
})
ip:string

simple-array 列类型

有一种称为simple-array的特殊列类型,它可以将原始数组值存储在单个字符串列中。 所有值都以逗号分隔

ts
@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number;
 
    @Column("simple-array")
    names: string[];
}

simple-json列类型

还有一个名为simple-json的特殊列类型,它可以存储任何可以通过 JSON.stringify 存储在数据库中的值。 当你的数据库中没有 json 类型而你又想存储和加载对象,该类型就很有用了。 例如:

ts
@Entity()
export class User {
    @PrimaryGeneratedColumn()
    id: number;
 
    @Column("simple-json")
    profile: { name: string; nickname: string };
}

屏蔽特定字段的返回

使用 @Column({ select: false })

TypeORM 提供了 select: false 属性,使得 password 默认不被查询到,但在需要时仍可以显式加载。

ts
@Entity('users')
export class User {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column()
  username: string;

  @Column({ select: false }) // 默认不查询 password 字段
  password: string;

  @Column()
  email: string;
}

查询时显式加载 password

ts
const user = await this.userRepository.findOne({
  where: { id: userId },
  select: ['id', 'username', 'password'], // 显式加载 password
});

使用 select 指定查询字段

如果某些查询仅需要部分字段,可以在 TypeORM 查询时通过 select 显式排除 password

ts
const users = await this.userRepository.find({
  select: ['id', 'username', 'email'], // 仅查询需要的字段
});

TypeORM的一对一映射

一对一的实体

在这里,用户User表和身份证IdCard表是一对一的关系。

user表的实体设计如下:

ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'varchar', length: 100, comment: '用户名' })
  username: string;
}

idcard表的实体设计如下:

ts
import { User } from 'src/modules/user/entities/user.entity';
import {
  Column,
  Entity,
  JoinColumn,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';

@Entity('id_card')
export class IdCard {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'varchar', length: 100, comment: '身份证号码' })
  cardNumber: string;

  // 在 IdCard 的 Entity 添加一个 user 列,指定它和 User 是 @OneToTone 一对一的关系。
  // 还要指定 @JoinColum 也就是外键列在 IdCard 对应的表里维护:
  @JoinColumn()
  @OneToOne(() => User)
  user: User;
}

一对一关联查询

ts
import { Injectable } from '@nestjs/common';
import { CreateIdcardDto } from './dto/create-idcard.dto';
import { UpdateIdcardDto } from './dto/update-idcard.dto';
import { InjectEntityManager } from '@nestjs/typeorm';
import { EntityManager } from 'typeorm';
import { IdCard } from './entities/idcard.entity';

@Injectable()
export class IdcardService {
  @InjectEntityManager()
  private idcardEntityManager: EntityManager;

  findAll() {
    return this.idcardEntityManager.find(IdCard, {
      // user就是在实体加入的JoinColumn列的名称user
      relations: ['user'],
      // 或者下面的方式也可以
      relations: {
        user: true
      }
    });
  }
}

查询出来的结果如下:

json
[
  {
    "id": 1,
    "cardNumber": "42xxxxxxxxxxxx55",
    "user": {
      "id": 1,
      "username": "陈刚"
    }
  }
]

TypeORM的一对多和多对一的映射

这里我们将@OneToMany添加到photos属性中,并将目标关系类型指定为Photo。 你可以在@ManyToOne / @OneToMany关系中省略@JoinColumn,除非你需要自定义关联列在数据库中的名称。 @ManyToOne可以单独使用,但@OneToMany必须搭配@ManyToOne使用。 如果你想使用@OneToMany,则需要@ManyToOne。 在你设置@ManyToOne的地方,相关实体将有"关联 id"和外键。

多对一/一对多是指 A 包含多个 B 实例的关系,但 B 只包含一个 A 实例。 让我们以UserPhoto 实体为例。 User 可以拥有多张 photos,但每张 photo 仅由一位 user 拥有。

Photo实体结构如下:

ts
import { User } from 'src/modules/user/entities/user.entity';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';

@Entity({ name: 'photo' })
export class Photo {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ comment: '照片地址' })
  url: string;

  // 一个用户可以拥有多张照片,因此在这里可以理解为Photo对于User是多对一的
  @ManyToOne(() => User, (user) => user.photos)
  user: User;
}

User实体结构如下:

ts
import { Photo } from 'src/modules/photo/entities/photo.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';

@Entity('users_demo')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ type: 'varchar', length: 100, comment: '用户名' })
  username: string;

  // 一个用户拥有多张图片,因此在User的实体内部是一对多的关系
  @OneToMany(() => Photo, (photo) => photo.user)
  photos: Photo[];
}