TypeORM框架(二)

Find 选项-基础选项

所有存储库和管理器find方法都接受可用于查询所需数据的特殊选项,而无需使用QueryBuilder

// select - 表示必须选择对象的哪些属性
userRepository.find({ select: ["firstName", "lastName"] });
// relations - 关系需要加载主体。 也可以加载子关系(join 和 leftJoinAndSelect 的简写)
userRepository.find({ relations: ["profile", "photos", "videos"] });
// join - 需要为实体执行联接,扩展版对的"relations"。
// where -查询实体的简单条件。
userRepository.find({ where: { firstName: "Timber", lastName: "Saw" } });
// 使用 OR 运算符查询:
userRepository.find({
where: [{ firstName: "Timber", lastName: "Saw" }, { firstName: "Stan", lastName: "Lee" }]
});
// order 排序 "ASC" | "DESC" | 1 | -1
userRepository.find({order: {id: "DESC"}});
// 分页
userRepository.find({skip: 5,take: 10});
// cache - 启用或禁用查询结果缓存
userRepository.find({cache: true});

Find 选项-进阶选项

TypeORM 提供了许多内置运算符,可用于创建更复杂的查询

// Not:SELECT * FROM "user" WHERE "firstName" != '张'
const loadedPosts = await userRepository.find({
firstName: Not("张") });
// LessThan:SELECT * FROM "user" WHERE "age" < 10
const loadedPosts = await userRepository.find({
age: LessThan(10) });
// LessThanOrEqual:将执行
SELECT * FROM "user" WHERE "age" <= 10
const loadedPosts = await userRepository.find({
age: LessThanOrEqual(10) });
// MoreThan:SELECT * FROM "user" WHERE "age" > 10
const loadedPosts = await userRepository.find({
age: MoreThan(10) });
// MoreThanOrEqual: SELECT * FROM "user" WHERE "age" > = 10
const loadedPosts = await userRepository.find({
age: MoreThanOrEqual(10) });
// Equal: SELECT * FROM "user" WHERE "age" = 10
const loadedPosts = await userRepository.find({
age: Equal(10) });
// Like:SELECT * FROM "user" WHERE "firstName" LIKE '%
张%'
const loadedPosts = await userRepository.find({
firstName: Like("%张%") });
// Between:
SELECT * FROM "user" WHERE "age" BETWEEN 1 AND 10
const loadedPosts = await userRepository.find({
age: Between(1, 10) });
// In: SELECT * FROM "user" WHERE "age" IN (10,20,30)
const loadedPosts = await userRepository.find({
age: In([10,20,30])
});

实体

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

实体列:由于数据库表由列组成,因此实体也必须由列组成。 标有@ Column的每个实体类属性都将映射到数据库表列

       主列:每个实体必须至少有一个主列。有几种类型的主要列:

       @PrimaryColumn() 创建一个主列,它可以获取任何类型的任何值。你也可以指定列类型。 如果未指定列类型,则将从属性类型自动推断。

       @PrimaryGeneratedColumn() 创建一个主列,该值将使用自动增量值自动生成。

       @PrimaryGeneratedColumn(“uuid”) 创建一个主列,该值将使用uuid自动生成,(Uuid 是一个独特的字符串 id)

       特殊列

       @CreateDateColumn 自动为实体插入日期。无需设置此列,该值将自动设置。

       @UpdateDateColumn 在每次调用实体管理器或存储库的save时,自动更新实体日期。无需设置此列,该值将自动设置。

       列类型

       @Column(“int”) 或者 @Column({ type: “int” })

       如果要指定其他类型参数,可以通过列选项来执行:例子:@Column(“varchar”, { length: 200 })

mysql的列类型

int, tinyint, smallint, mediumint, bigint, float, double, dec, decimal, numeric, date, datetime, timestamp, time, year, char, varchar, nvarchar, text, tinytext, mediumtext, blob, longtext, tinyblob, mediumblob, longblob, enum, json, binary, geometry, point, linestring,polygon, multipoint, multilinestring, multipolygon, geometrycollection

enum 列类型

export enum UserRole {
  ADMIN = "admin",
  EDITOR = "editor",
  GHOST = "ghost" 
}
@Entity()
export class User { 
  @Column({
    type: "enum",
    enum: UserRole,
    default: UserRole.GHOST
  })
  role: UserRole
}

simple-array的列类型:它可以将原始数组值存储在单个字符串列中。 所有值都以逗号分隔。 返回时,也将作为数组方式返回

@Entity()
export class User { 
    @Column("simple-array")
    names: string[];
}
const user = new User();
user.names = ["Alexander", "Alex", "Sasha", "Shurik"];

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

@Entity()
export class User { 
    @Column("simple-json")
    profile: { name: string; nickname: string };
}
const user = new User();
user.profile = { name: "John", nickname: "Malkovich" };

列选项

列选项定义实体列的其他选项。 你可以在@ Column上指定列选项:

ColumnOptions中可用选项列表:

type: ColumnType - 列类型。

name: string - 数据库表中的列名。默认情况下,列名称是从属性的名称生成的。 你也可以通过指定自己的名称来更改它。

length: number - 列类型的长度。 例如,如果要创建varchar(150)类型,请指定列类型和长度选项。

nullable: boolean - 在数据库中使列NULL或NOT NULL。 默认情况下,列是nullable:false。

update: boolean - 指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。 默认值为"true"。

select: boolean - 定义在进行查询时是否默认隐藏此列。 设置为false时,列数据不会显示标准查询。 默认情况下,列是select:true

default: string - 添加数据库级列的DEFAULT值。

primary: boolean - 将列标记为主要列。 使用方式和@ PrimaryColumn相同。

unique: boolean - 将列标记为唯一列(创建唯一约束)。

comment: string - 数据库列备注,并非所有数据库类型都支持。

enum: string[]|AnyEnum - 在enum列类型中使用,以指定允许的枚举值列表。 你也可以指定数组或指定枚举类。

@Column({
  type: "varchar",
  length: 150,
  unique: true,
  // ...
})
name: string;

嵌入实体类

通过使用embedded columns,可以减少应用程序中的重复

嵌入列是一个列,它接受具有自己列的类,并将这些列合并到当前实体的数据库表中。

// Name.ts
import {Entity, Column} from "typeorm";
export class Name { 

    @Column()
    first: string; 
    
    @Column()
    last: string; 
}
//User.ts
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
import {Name} from "./Name";

@Entity()
export class User { 
    @PrimaryGeneratedColumn()
    id: string; 
    @Column(type => Name)
    name: Name; 
    @Column()
    isActive: boolean; 
}

关系

什么是关系

关系可以帮助你轻松地与相关实体合作。 有几种类型的关系

一对一 使用 @OneToOne

多对一 使用 @ManyToOne

一对多 使用 @OneToMany

多对多 使用 @ManyToMany

关系选项

eager: boolean - 如果设置为 true,则在此实体上使用find * 或QueryBuilder时,将始终使用主实体加载关系

cascade: boolean - 如果设置为 true,则将插入相关对象并在数据库中更新。

onDelete: “RESTRICT”|“CASCADE”|“SET NULL” - 指定删除引用对象时外键的行为方式

primary: boolean - 指示此关系的列是否为主列。

nullable: boolean -指示此关系的列是否可为空。 默认情况下是可空。

orphanedRowAction: “nullify” | “delete” - 将子行从其父行中删除后,确定该子行是孤立的(默认值)还是删除的。

一对一的关系

一对一是一种 A 只包含一个 B 实例,而 B 只包含一个 A 实例的关系。 我们以User和Profile实体为例。

用户只能拥有一个配置文件,并且一个配置文件仅由一个用户拥有。

@Entity()
export class Profile { 
    @PrimaryGeneratedColumn()
    id: number; 
    
    @Column()
    gender: string; 
    
    @Column()
    photo: string; 
}
@Entity()
export class User { 
    @PrimaryGeneratedColumn()
    id: number; 
    
    @Column()
    name: string; 
    
    @OneToOne(() => Profile)
    @JoinColumn()
    profile: Profile; 
}

这里我们将@OneToOne添加到profile并将目标关系类型指定为Profile。 我们还添加了@JoinColumn,这是必选项并且只能在关系的一侧设置。你设置@JoinColumn的哪一方,哪一方的表将包含一个"relation id"和目标实体表的外键。

同样,@JoinColumn必须仅设置在关系的一侧且必须在数据库表中具有外键的一侧。

const profile = new Profile();
profile.gender = "male";
profile.photo = "me.jpg";

await profileRepository.save(profile);

const user = new User();
user.name = "Joe Smith";
user.profile = profile;
await userRepository.save(user)

const users = await userRepository.findOne({
    relations: ["profile"],
    where:{id:1} 
});

多对一/一对多的关系

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

@Entity()
export default class Photo { 
    @PrimaryGeneratedColumn()
    id: number; 

    @Column()
    url: string; 

    @ManyToOne(() => User, user => user.photos)
    user: User; 
}
@Entity()
export default class User { 
    @PrimaryGeneratedColumn()
    id: number; 

    @Column()
    name: string; 

    @OneToOne(() => Profile) 
    @JoinColumn()
    profile: Profile; 

    @OneToMany(() => Photo, photo => photo.user)
    photos: Photo[]; 
}

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

需要查询带有 photos 的 user,必须在FindOptions中指定关系

const photo1 = new Photo();
photo1.url = "me.jpg";
await photoRepository.save(photo1);

const photo2 = new Photo();
photo2.url = "me-and-bears.jpg";
await photoRepository.save(photo2);

const user = new User();
user.name = "John";
user.photos = [photo1, photo2];
await userRepository.save(user);

const users = await userRepository.find({ relations: ["photos"] });
const photos = await photoRepository.find({ relations: ["user"] });

多对多的关系

多对多是一种 A 包含多个 B 实例,而 B 包含多个 A 实例的关系。 我们以Question 和 Category 实体为例。 Question 可以有多个 categories, 每个category 可以有多个 questions

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()
export default class Category { 
    @PrimaryGeneratedColumn()
    id: number; 

    @Column()
    name: string; 
}
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany,
JoinTable } from "typeorm";
import Category from "./Category";

@Entity()
Export default class Question { 
    @PrimaryGeneratedColumn()
    id: number; 

    @Column()
    title: string; 

    @Column()
    text: string; 

    @ManyToMany(() => Category) 
    @JoinTable()
    categories: Category[]; 
}

@JoinTable()是@ManyToMany关系所必需的

要在 categories 里面加载 question,你必须在FindOptions中指定关系

const category1 = new Category();
category1.name = "animals";
await categoryRepository.save(category1);

const category2 = new Category();
category2.name = "zoo";
await categoryRepository.save(category2);

const question = new Question();
question.text = '文本'
question.title = '标题'
question.categories = [category1, category2];
await questionRepository.save(question);
const questions = await questionRepository.find({ relations: ["categories"] });

使用 Query Builder

QueryBuilder是 TypeORM 最强大的功能之一 ,它允许你使用优雅便捷的语法构建 SQL 查询,执行并获得自动转换的实体。

// SELECT * FROM users user WHERE user.id = 1
const firstUser = await userRepository
    .createQueryBuilder("user") 
    .where("user.id = :id", { id: 1 }) 
    .getOne();

更多查看使用 Query Builder 查询 | TypeORM 中文文档 (biunav.com)

你可能感兴趣的:(TypeORM框架)