• TypeORM 框架


    TypeORM 框架

    认识 TypeORM

    • TypeORM是一个ORM (opens new window)框架,它可以运行在 NodeJSBrowserCordovaPhoneGapIonicReact NativeExpoElectron平台上,可以与TypeScriptJavaScript (ES5,ES6,ES7,ES8)一起使用。 它的目标是始终支持最新的JavaScript特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。
    • 不同于现有的所有其他JavaScript ORM框架,TypeORM支持Active RecordData Mapper模式,这意味着你可以以最高效的方式编写高质量的、松耦合的、可扩展的、可维护的应用程序。

    TypeORM 的特性

    • 支持DataMapperActiveRecord (随你选择)
    • 实体和列
    • 数据库特性列类型
    • 实体管理
    • 存储库和自定义存储库
    • 清晰的对象关系模型
    • 关联(关系)
    • 贪婪和延迟关系
    • 单向的,双向的和自引用的关系
    • 支持多重继承模式
    • 级联
    • 索引
    • 事务
    • 迁移和自动迁移
    • 连接池
    • 主从复制
    • 使用多个数据库类型
    • 跨数据库和跨模式查询
    • 优雅的语法,灵活而强大的 QueryBuilder
    • 左联接和内联接
    • 使用联查查询的适当分页
    • 查询缓存
    • 原始结果流
    • 日志
    • 监听者和订阅者(钩子)
    • 支持闭包表模式
    • 在模型或者分离的配置文件中声明模式
    • json / xml / yml / env 格式的连接配置
    • 支持 MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / sql.js
    • 支持 MongoDB NoSQL 数据库
    • 可在 NodeJS / 浏览器 / Ionic / Cordova / React Native / Expo / Electron 平台上使用
    • 支持 TypeScriptJavaScript
    • 生成高性能、灵活、清晰和可维护的代码
    • 遵循所有可能的最佳实践
    • 命令行工具

    安装(一)

    • 通过npm安装:
      • npm install typeorm --save
    • 你还需要安装reflect-metadata:
      • npm install reflect-metadata --save
    • 并且需要在应用程序的全局位置导入(例如在app.ts中)
      • import "reflect-metadata";
    • 你可能还需要安装node typings(以此来使用Node的智能提示):
      • npm install @types/node –save
    • 安装数据库驱动MySQL
      • npm install mysql --save(也可以安装mysql2)
    • 此外,请确保你使用的是TypeScript编译器版本2.3或更高版本,并且已经在tsconfig.json中启用了以下设置:
      • "emitDecoratorMetadata": true,
      • "experimentalDecorators": true,
    • 你可能还需要在编译器选项的lib中启用es ,或者从@types安装es6-shim

    安装(二)

    • 开始使用TypeORM的最快方法是使用其CLI命令(脚手架)生成启动项目。 只有在NodeJS应用程序中使用TypeORM时,此操作才有效。

    • 首先全局安装TypeORM:

      • npm install typeorm –g

        在这里插入图片描述

    • 然后转到要创建新项目的目录并运行命令:

      • typeorm init --name LearnTypeorm --database mysql

        在这里插入图片描述

    • 其中name是项目的名称,database是您将使用的数据库。

      • 数据库可以是以下值之一: mysql, mariadb, postgres, sqlite, mssql, oracle, mongodb, cordova, react-native, expo, nativescript.
      • 你还可以在现有node项目上运行typeorm init,但要注意,此操作可能会覆盖已有的某些文件。
    • 然后用编辑软件打开创建好的项目,会先出现一个md说明文件

      在这里插入图片描述

      • 第一步:npm i

        在这里插入图片描述

      • 第二步:删掉src文件夹下面的migration文件

      • 第三步:配置tsconfig.json文件(把"module":"ESNext"换成"module": "CommonJS"

        在这里插入图片描述

      • 第四步:配置ormconfig.json

        在这里插入图片描述

        {
          "type": "mysql",
          "host": "localhost",
          "port": 3306,
          "username": "root",
          "password": "123456",
          "database": "mall",
          "synchronize": true,
          "logging": false,
          "entities": [
            "src/entity/**/*.ts"
          ],
          "cli": {
            "entitiesDir": "src/entity"
          }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16

    包的依赖(package.json

    • 注意版本:下面的文件如果执行出现错误,可能是你的包版本太高导致的

      {
         "name": "learn_typeorm",
         "version": "0.0.1",
         "description": "Awesome project developed with TypeORM.",
         "devDependencies": {
            "ts-node": "3.3.0",
            "@types/node": "^8.0.29",
            "typescript": "3.3.3333"
         },
         "dependencies": {
            "mysql": "^2.14.1",
            "reflect-metadata": "^0.1.10",
            "ts-node-dev": "^1.1.8",
            "typeorm": "0.2.37"
         },
         "scripts": {
            "start": "ts-node-dev src/find进阶选项.ts"
         }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19

    数据库配置文件

    • 大多数情况下,我们希望将连接选项存储在单独的配置文件中,因为此方式使管理变得更方便和容易。 TypeORM支持多个配置源。你只需要在应用程序的根目录(package.json附近)中创建一个ormconfig.[format]文件存放连接配置,并在应用程序中调用createConnection(),而不传递任何参数配置
    • 支持的ormconfig 文件格式有:.json, .js, .env, .yml.xml

    Typeorm 使用哪个配置文件

    • 有时你可能希望使用不同格式的多个配置。 当调用getConnectionOptions()或尝试在没有连接选项的情况下使用createConnection()时,Typeorm将尝试按以下顺序加载配置:
    • 从另一个ormconfig.[format]文件,按此顺序:[js,ts,json,yml,yaml,xml]
    • 注意,Typeorm将使用找到的第一个有效方法,而不会加载其他方法。 例如,如果在环境中找到配置,Typeorm将不会加载ormconfig.[format]文件。

    ConnectionOptions(一)

    • 连接选项是你传递给createConnection或在ormconfig文件中定义的连接配置。不同的数据库有自己的特定连接选项。
    • 常用的连接选项:
      • type - 数据库类型。你必须指定要使用的数据库引擎。该值可以是"mysql...."。此选项是必需的。
      • name - 连接名。 在使用 getConnection(name: string)ConnectionManager.get(name: string)时候需要用到。不同连接的连接名称不能相同,它们都必须是唯一的。如果没有给出连接名称,那么它将被设置为"default"。
      • entities - 要加载并用于此连接的实体。接受要加载的实体类和目录路径。目录支持 glob 模式。示例:entities: [Post, Category, "entity/*.js", "modules/**/entity/*.js"]
      • subscribers - 要加载并用于此连接的订阅者。接受要加载的实体类和目录。
      • migrations - 要加载和用于此连接的迁移。接受要加载的迁移类和目录
      • logging - 指示是否启用日志记录。如果设置为true,则将启用查询和错误日志记录。你还可以指定要启用的不同类型的日志记录,例如["query", "error", "schema"]

    ConnectionOptions(二)

    • maxQueryExecutionTime - 如果查询执行时间超过此给定的最大执行时间(以毫秒为单位),则 logger 将记录此查询。
    • entityPrefix - 给此数据库连接上的所有表(或集合)加的前缀。
    • dropSchema - 每次建立连接时删除架构。请注意此选项,不要在生产环境中使用它,否则将丢失所有生产数据。但是此选项在调试和开发期间非常有用。
    • synchronize - 指示是否在每次应用程序启动时自动创建数据库架构。 请注意此选项,不要在生产环境中使用它,否则将丢失所有生产数据。但是此选项在调试和开发期间非常有用。
    • cache - 启用实体结果缓存。
    • cli.entitiesDir - CLI 默认情况下创建实体的目录。
    • cli.migrationsDir - CLI 默认情况下创建迁移的目录。
    • cli.subscribersDir - CLI 默认情况下创建订阅者的目录。

    连接Connection

    • ormconfig文件加载所有连接选项

      import 'reflect-metadata'
      import {createConnection} from "typeorm";
      import {User} from "./entity/User";
      
      const getConnection = async ()=>{
          // 创建数据库连接
          const connection = await createConnection()
          console.log(connection)
      }
      
      getConnection()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    使用 EntityManager

    • Repository就像EntityManager一样,但其操作仅限于具体实体。

      // User.ts
      
      import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
      
      @Entity()
      export class User {
      
          @PrimaryGeneratedColumn()
          id: number
      
          @Column()
          firstName: string
      
          @Column()
          lastName: string
      
          @Column()
          age: number
      
          // 构造函数
          constructor(firstName: string, lastName: string, age: number,id?:number) {
              this.firstName = firstName;
              this.lastName = lastName;
              this.age = age;
              this.id = id
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      // index.ts
      
      import 'reflect-metadata'
      import {createConnection, getManager} from "typeorm";
      import {User} from "./entity/User";
      
      createConnection().then(()=>{
          // 获取实体管理器
          const entityManger = getManager()
          /**
           * 添加
           */
          const save = async ()=>{
              const user:User = new User('张','三',20)
              // 通过实体管理器添加用户
              const res = await entityManger.save<User>(user)
              console.log(res)
          }
          // save()
      
      
          /**
           * 查询所有
           */
          const queryAll = async ()=>{
              // 查询全部
              const [users]:User[] = await entityManger.find<User>(User)
              console.log(users)
          }
          // queryAll()
      
          /**
           * 修改
           */
          const edit = async () => {
              const user:User = new User('李','四',20,1)
              const res = await entityManger.save<User>(user)
              console.log(res)
          }
          // edit()
      
          /**
           * 删除
           */
          const del = async ()=>{
              const {affected} = await entityManger.delete<User>(User,[3,4])
              console.log(affected?'删除成功':'删除失败')
          }
          // del()
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50

    使用 Repository

    • Repository就像EntityManager一样,但其操作仅限于具体实体。

      // User.ts
      
      import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
      
      @Entity()
      export class User {
      
          @PrimaryGeneratedColumn()
          id: number
      
          @Column()
          firstName: string
      
          @Column()
          lastName: string
      
          @Column()
          age: number
      
          // 构造函数
          constructor(firstName: string, lastName: string, age: number,id?:number) {
              this.firstName = firstName;
              this.lastName = lastName;
              this.age = age;
              this.id = id
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      // index.ts
      
      import 'reflect-metadata'
      import {createConnection, getRepository} from "typeorm";
      import {User} from "./entity/User";
      
      /**
       * Repository
       */
      
      createConnection().then((connection)=>{
          // 获取存储库
          const userRepository = getRepository(User)
      
          /**
           * 添加
           */
          const save = async ()=>{
              const user:User = new User('刘','能',30)
              const res = await userRepository.save(user)
              console.log(res)
          }
          // save()
      
          /**
           * 查询所有
           */
          const queryAll = async ()=>{
              const users:User[] = await userRepository.find()
              console.log(users)
          }
          // queryAll()
      
          /**
           * 修改
           */
          const edit = async () => {
              const user:User = new User('刘','能',11,7)
              const res = await userRepository.save(user)
              console.log(res)
          }
          // edit()
      
          /**
           * 删除
           */
          const del = async ()=>{
              const {affected} = await userRepository.delete(5)
              console.log(affected?'删除成功':'删除失败')
          }
          del() 
      })                  
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52

    自定义存储库

    • 可以创建一个自定义存储库,其中应包含使用数据库的方法。 通常为单个实体创建自定义存储库,并包含其特定的查询

      import "reflect-metadata";   // 使用装饰器需要导入
      import {EntityRepository, Repository, getCustomRepository, createConnection} from 'typeorm';
      import {User} from "./entity/User";
      
      // 装饰器 自定义的用户存储库存储库
      @EntityRepository(User)
      class UserRepository extends Repository<User>{
          // 自定义的方法
          findByName(firstName: string, lastName: string) {
              return this.findOne({firstName,lastName})
          }
      }
      
      createConnection().then(()=>{
          // 获取自定义的存储库的实例 参数就是自定义的存储库
          const userRepository= getCustomRepository(UserRepository)
      
          // const save = async()=>{
          //     const user:User = new User('王','五',18)
          //     const res = await userRepository.save(user)
          //     console.log(res)
          // }
          // save()
      
          const queryByName = async ()=>{
              const user = await userRepository.findByName('王','五')
              console.log(user)
          }
          queryByName()
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30

    Find 选项-基础选项

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

      // index.ts
      
      import "reflect-metadata";
      import {createConnection, getRepository} from "typeorm";
      import {User} from "./entity/User";   // 使用装饰器需要导入
      
      createConnection().then(async ()=>{
          const userRepository = getRepository(User)
      
          const res = await userRepository.find({
              // 限制查询字段
              select:['id','firstName','lastName','age'],
      
              // 查询条件
              // where:{firstName:'张'}
      
              // or 使用数组
              where:[{firstName:'张'},{firstName: '刘'}],
      
              // order 排序
              // ASC 1 升序
              // DESC -1 降序
              order:{id:'DESC'},
      
              // 分页
              // skip 起始位置
              skip:0,
              // take 数量
              take:1,
      
              // 是否开启缓存
              cache:true
          })
          console.log(res)
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35

    Find 选项-进阶选项

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

      import "reflect-metadata";
      import {
          createConnection,
          getRepository,
          LessThan,
          LessThanOrEqual,
          Not,
          MoreThan,
          MoreThanOrEqual,
          Equal, Like, Between, In
      } from "typeorm";
      import {User} from "./entity/User";
      
      /**
       * find 选项  - 进阶
       */
      
      // 创建数据库连接
      createConnection().then(async()=> {
          // 获取用户的存储库
          const userRepository = getRepository(User)
      
          // Not:SELECT * FROM "user" WHERE "firstName" != '张';
          // user 表中不含有 firstName 为 张 的
          const users: User[] = await userRepository.find({
              firstName:Not('张')
          })
          console.log("不信张的列表",users)
      
          // LessThan:SELECT * FROM "user" WHERE "age" < 15
          // user 表中 age 小于 15 的列表
          const users1: User[] = await userRepository.find({
              age:LessThan(15)
          })
          console.log("年龄小于15的列表",users1)
      
          // LessThanOrEqual:SELECT * FROM "user" WHERE "age" <= 11
          // user 表中 age 小于等于 11 的列表
          const users2: User[] = await userRepository.find({
              age:LessThanOrEqual (11)
          })
          console.log("年龄小于等于11的列表",users2)
      
          // MoreThan:SELECT * FROM "user" WHERE "age" > 10
          // user 表中 age 大于 10 的列表
          const users3: User[] = await userRepository.find({
              age:MoreThan (10)
          })
          console.log("年龄大于10的列表",users3)
      
          // MoreThanOrEqual: SELECT * FROM "user" WHERE "age" > = 20
          // user 表中 age 大于等于 20 的列表
          const users4: User[] = await userRepository.find({
              age:MoreThanOrEqual (20)
          })
          console.log("年龄大于等于20的列表",users4)
      
          // Equal: SELECT * FROM "user" WHERE "age" = 11
          // user 表中 age 大于等于 20 的列表
          const users5: User[] = await userRepository.find({
              age:Equal (11)
          })
          console.log("年龄等于11的列表",users5)
      
          // Like:SELECT * FROM "user" WHERE "firstName" LIKE '%张%'
          // 模糊查询 user 表中 firstName 姓 张 的列表
          const users6: User[] = await userRepository.find({
              firstName:Like ('%张%')
          })
          console.log("模糊查询姓张的列表",users6)
      
          // Between:SELECT * FROM "user" WHERE "age" BETWEEN 1 AND 10
          // 查询 user 表中 age 在 1 到 11 之间的 包括1和11
          const users7: User[] = await userRepository.find({
              age:Between (1,11)
          })
          console.log("查询年龄1到11之间的",users7)
      
          // In: SELECT * FROM "user" WHERE "age" IN (11,20)
          // 查询 user 表中 age 在 11和20
          const users8: User[] = await userRepository.find({
              age:In([11,20])
          })
          console.log(users8)
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85

    实体

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

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

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

        • @PrimaryColumn()创建一个主列,它可以获取任何类型的任何值。你也可以指定列类型。 如果未指定列类型,则将从属性类型自动推断。
        • @PrimaryGeneratedColumn()创建一个主列,该值将使用自动增量值自动生成。
        • @PrimaryGeneratedColumn("uuid")创建一个主列,该值将使用uuid自动生成,(Uuid 是一个独特的字符串id)
      • 特殊列:

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

        • @Column(“int”)或者@Column({ type: "int" })
        • 如果要指定其他类型参数,可以通过列选项来执行:例子:@Column("varchar", { length: 200 })
        import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn} from "typeorm";
        
        /**
         * 实体类 => 数据库表
         * 添加了 @Entity 装饰器就会被 typeorm 去映射,判断表是否存在,不存在表才会被创建,存在不做处理
         * 你要想创建类的表结构,就需要创建 @Entity()
         */
        
        @Entity()
        export default class Person {
            // 主键:PrimaryColumn
            // @PrimaryGeneratedColumn('uuid') 传入uuid会自动生成uuid作为主键
            // 自动增长的主键
            @PrimaryGeneratedColumn()
            id:number
        
            // 自动添加创建时间
            @CreateDateColumn()
            createAt:Date
        
            // 自动修改时间
            @UpdateDateColumn()
            updateAt:Date
        
            // 列 name varchar(255)
            // 添加了 @Column() 会映射为表中的字段
            // 可以指定列的类型 也可以限制长度
            @Column('varchar',{length:20})
            name:string
        
            // 可以指定列的类型
            @Column('int')
            gander:number
        
            constructor(name: string) {
                this.name = name;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38

    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列类型

      import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn} from "typeorm";
      
      export enum PersonRole {
          STUDENT = 'student',
          TEACHER = 'teacher'
      }
      
      /**
       * 实体类 => 数据库表
       * 添加了 @Entity 装饰器就会被 typeorm 去映射,判断表是否存在,不存在表才会被创建,存在不做处理
       * 你要想创建类的表结构,就需要创建 @Entity()
       */
      
      @Entity()
      export default class Person {
          // 主键:PrimaryColumn
          // @PrimaryGeneratedColumn('uuid') 传入uuid会自动生成uuid作为主键
          // 自动增长的主键
          @PrimaryGeneratedColumn()
          id:number
      
          // 自动添加创建时间
          @CreateDateColumn()
          createAt:Date
      
          // 自动修改时间
          @UpdateDateColumn()
          updateAt:Date
      
          // 列 name varchar(255)
          // 添加了 @Column() 会映射为表中的字段
          // 可以指定列的类型 也可以限制长度
          @Column('varchar',{length:20})
          name:string
      
          // 可以指定列的类型
          @Column('int')
          gander:number
      
          @Column({
              type:"enum",
              enum:PersonRole
          })
          role:PersonRole
      
          constructor(name: string, gander: number, role: PersonRole) {
              this.name = name;
              this.gander = gander;
              this.role = role;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
    • simple-array的列类型: 它可以将原始数组值存储在单个字符串列中。 所有值都以逗号分隔。 返回时,也将作为数组方式返回

      import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn} from "typeorm";
      
      export enum PersonRole {
          STUDENT = 'student',
          TEACHER = 'teacher'
      }
      
      /**
       * 实体类 => 数据库表
       * 添加了 @Entity 装饰器就会被 typeorm 去映射,判断表是否存在,不存在表才会被创建,存在不做处理
       * 你要想创建类的表结构,就需要创建 @Entity()
       */
      
      @Entity()
      export default class Person {
          // 主键:PrimaryColumn
          // @PrimaryGeneratedColumn('uuid') 传入uuid会自动生成uuid作为主键
          // 自动增长的主键
          @PrimaryGeneratedColumn()
          id:number
      
          // 自动添加创建时间
          @CreateDateColumn()
          createAt:Date
      
          // 自动修改时间
          @UpdateDateColumn()
          updateAt:Date
      
          // 列 name varchar(255)
          // 添加了 @Column() 会映射为表中的字段
          // 可以指定列的类型 也可以限制长度
          @Column('varchar',{length:20})
          name:string
      
          // 可以指定列的类型
          @Column('int')
          gander:number
      
          @Column({
              type:"enum",
              enum:PersonRole
          })
          role:PersonRole
      
          @Column({
              // 列是一个数组
              type:'simple-array'
          })
          nickName:Array<string>
      
          constructor(name: string, gander: number, role: PersonRole) {
              this.name = name;
              this.gander = gander;
              this.role = role;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57

    mysql的列类型(二)

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

      import {Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn} from "typeorm";
      
      export enum PersonRole {
          STUDENT = 'student',
          TEACHER = 'teacher'
      }
      
      /**
       * 实体类 => 数据库表
       * 添加了 @Entity 装饰器就会被 typeorm 去映射,判断表是否存在,不存在表才会被创建,存在不做处理
       * 你要想创建类的表结构,就需要创建 @Entity()
       */
      
      @Entity()
      export default class Person {
          // 主键:PrimaryColumn
          // @PrimaryGeneratedColumn('uuid') 传入uuid会自动生成uuid作为主键
          // 自动增长的主键
          @PrimaryGeneratedColumn()
          id:number
      
          // 自动添加创建时间
          @CreateDateColumn()
          createAt:Date
      
          // 自动修改时间
          @UpdateDateColumn()
          updateAt:Date
      
          // 列 name varchar(255)
          // 添加了 @Column() 会映射为表中的字段
          // 可以指定列的类型 也可以限制长度
          @Column('varchar',{length:20})
          name:string
      
          // 可以指定列的类型
          @Column('int')
          gander:number
      
          @Column({
              type:"enum",
              enum:PersonRole
          })
          role:PersonRole
      
          @Column({
              // 列是一个数组
              type:'simple-array'
          })
          nickName:Array<string>
      
          @Column('simple-json')
          perfile:{name:string,nickName:string}
      
          constructor(name: string, gander: number, role: PersonRole) {
              this.name = name;
              this.gander = gander;
              this.role = role;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60

    列选项

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

      • ColumnOptions中可用选项列表:

      • type: ColumnType - 列类型。

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

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

      • nullable: boolean - 在数据库中使列NULLNOT 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列类型中使用,以指定允许的枚举值列表。 你也可以指定数组或指定枚举类。

        import {Column, Entity, PrimaryGeneratedColumn} from "typeorm";
        
        @Entity()
        export class Student {
            @PrimaryGeneratedColumn()
            id:number
        
            @Column({
        
                // 自定义字段的类型
                type:'varchar',
        
                // 自定义字段的名称
                name:'sname',
        
                // 自定义字段的长度
                length:20,
        
                // not null 允许为空 false 不为空
                nullable:true,
        
                update:true,
        
                // false 查询时不显示
                select:false,
        
                // 列的默认值
                default:'123',
        
                // 唯一约束
                unique:false,
        
                // 列的注释
                comment:'姓名',
            })
            name:string
        
        
            constructor(name: string) {
                this.name = name;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        import 'reflect-metadata'
        import {createConnection, getRepository} from "typeorm";
        import {Student} from "./entity/Student";
        
        
        createConnection().then(async ()=>{
            const studentRepository  = getRepository(Student)
        
            // 添加
            const stu = new Student('张三')
            await studentRepository.save(stu)
        
            // 查询
            const student:Student[] = await studentRepository.find()
            console.log(student)
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16

    嵌入实体类

    • 通过使用embedded columns,可以减少应用程序中的重复
    • 嵌入列是一个列,它接受具有自己列的类,并将这些列合并到当前实体的数据库表中。

    关系

    • 什么是关系
    • 关系可以帮助你轻松地与相关实体合作。 有几种类型的关系
      • 一对一 使用 @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实例的关系。 我们以UsersProfile实体为例。

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

      // Profile.ts
      import {Column, Entity, PrimaryGeneratedColumn} from "typeorm";
      
      @Entity()
      export class Profile {
          @PrimaryGeneratedColumn()
          id:number
      
          @Column()
          gander:number
      
      
          constructor(gander: number) {
              this.gander = gander;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      // Users.ts
      import {Column, Entity, JoinColumn, OneToOne, PrimaryGeneratedColumn} from "typeorm";
      import {Profile} from "./Profile";
      
      @Entity()
      export class Users {
          @PrimaryGeneratedColumn()
          id:number
      
          @Column()
          name:string
      
          // OneToOne 一对一 指定关系
          @OneToOne(()=>Profile)
          // 外键
          @JoinColumn()
          profile:Profile
      
      
          constructor(name: string, profile: Profile) {
              this.name = name;
              this.profile = profile;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    • 这里我们将@OneToOne添加到profile并将目标关系类型指定为Profile。 我们还添加了@JoinColumn,这是必选项并且只能在关系的一侧设置。你设置@JoinColumn的哪一方,哪一方的表将包含一个"relation id"和目标实体表的外键。

    一对一的关系(二)

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

      // 一对一.ts
      import {createConnection, getRepository} from "typeorm";
      import {Profile} from "./entity/Profile";
      import {Users} from "./entity/Users";
      
      createConnection().then(()=>{
          const usersRepository = getRepository(Users)
          const profileRepository = getRepository(Profile)
      
          const save = async ()=>{
              // 创建 profile 对象
              const profile = new Profile(20)
              // 添加 profile 信息到数据库
              await profileRepository.save(profile)
      
              // 创建 users 对象
              const users = new Users('张三',profile)
              // 添加 users 信息到数据库
              const res = await usersRepository.save(users)
              console.log(res)
          }
          // save()
      
          // 查询
          const queryOne = async () =>{
              const users = await  usersRepository.findOne({
                  relations:['profile'],
                  where:{id:1}
              })
              console.log(users)
          }
          queryOne()
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33

    多对一/一对多的关系(一)

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

      // Photo.ts
      
      import {Column, Entity, ManyToOne, PrimaryGeneratedColumn} from "typeorm";
      import {User} from "./User";
      
      @Entity()
      export class Photo{
          @PrimaryGeneratedColumn()
          id:number
      
          @Column()
          url:string
      
          @ManyToOne(()=>User,person =>person.photos)
          person:User
      
      
          constructor(url: string) {
              this.url = url;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      // User.ts
      
      import {Column, Entity, OneToMany, PrimaryGeneratedColumn} from "typeorm";
      import {Photo} from "./Photo";
      @Entity()
      export class User {
          @PrimaryGeneratedColumn()
          id:number
      
          @OneToMany(()=>Photo,photo=> photo.person)
          photos:Photo[]
      
      
          constructor(photos: Photo[]) {
              this.photos = photos;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    • 这里我们将@OneToMany添加到photos属性中,并将目标关系类型指定为Photo。 你可以在@ManyToOne / @OneToMany关系中省略@JoinColumn,除非你需要自定义关联列在数据库中的名称。 @ManyToOne可以单独使用,但@OneToMany必须搭配@ManyToOne使用。 如果你想使用

      @OneToMany,则需要@ManyToOne。 在你设置@ManyToOne的地方,相关实体将有"关联 id"外键

    多对一/一对多的关系(二)

    • 需要查询带有photosuser,必须在FindOptions中指定关系

      import {createConnection, getRepository} from "typeorm";
      import {User} from "./entity/User";
      import {Photo} from "./entity/Photo";
      
      createConnection().then(()=>{
          const userRepository = getRepository(User)
          const photoRepository = getRepository(Photo)
      
          const save = async () => {
              const photo1 = new Photo('./img/01.jpg')
              const photo2 = new Photo('./img/02.jpg')
              await photoRepository.save([photo1,photo2])
      
              const user = new User([photo1,photo2])
              const res = await userRepository.save(user)
              console.log(res)
          }
          // save()
      
          const queryAll = async () =>{
              const res = await userRepository.find({
                  relations:['photos']
              })
              console.log(res)
          }
          queryAll()
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

    多对多的关系(一)

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

      // Category 类别
      import {Column, Entity, PrimaryGeneratedColumn} from "typeorm";
      
      @Entity()
      export class Category {
          @PrimaryGeneratedColumn()
          id:number
      
          @Column()
          name:string
      
      
          constructor(name: string) {
              this.name = name;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      // Question 问题
      import {Column, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn} from "typeorm";
      import {Category} from "./Category";
      
      @Entity()
      export class Question {
          @PrimaryGeneratedColumn()
          id:number
      
          @Column()
          title:string
      
          @Column()
          text:string
      
          @ManyToMany(()=>Category)
          @JoinTable()
          categories:Category[]
      
          constructor(title: string, text: string, categories: Category[]) {
              this.title = title;
              this.text = text;
              this.categories = categories;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
    • @JoinTable()@ManyToMany关系所必需的

    多对多的关系(二)

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

      import {createConnection, getRepository} from "typeorm";
      import {Category} from "./entity/Category";
      import {Question} from "./entity/Question";
      
      createConnection().then(()=>{
          const categoryRepository = getRepository(Category)
          const questionRepository = getRepository(Question)
      
          const save = async () =>{
              const category1 = new Category('animals')
              const category2 = new Category('zoo ')
              await categoryRepository.save([category1,category2])
      
              const question = new Question('标题','文本',[category1,category2])
              const res =  await questionRepository.save(question)
              console.log(res)
          }
          // save()
      
          const queryAll = async ()=>{
              const res = await questionRepository.find({
                  relations:['categories']
              })
              console.log(res)
          }
          queryAll()
      })
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

    使用 Query Builder

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

    逆向生成数据库模型

    • 首先全局安装:npm install typeorm-model-generator
    • 然后逆向生成代码:typeorm-model-generator -h localhost -d mall -u root -x 123456 -e mysql -o entity
      • -h localhost -d 数据库名字 -p 端口 -u 用户名 -x 密码 -e 数据库类型
      • -o entities表示输出到指定的文件夹
  • 相关阅读:
    背包问题总复习(纯理论)
    【BOOST C++ 10 时间数据】(2)本地独立时间
    类和对象(封装)
    Git一台电脑同时绑定两个账号(如gitlab,github)
    Hologres 共享集群助力淘宝订阅极致精细化运营
    完美解决Echarts X坐标轴下方文字最后一个字体加粗颜色加深的问题
    【计网】二、物理层
    数仓常用排序详解
    5分钟快速上手 pytest 测试框架
    发现智能合约中的 bug 的 7 个方法
  • 原文地址:https://blog.csdn.net/HTML_Z/article/details/125546660