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"
        }
      }
      

包的依赖(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"
       }
    }
    

数据库配置文件

  • 大多数情况下,我们希望将连接选项存储在单独的配置文件中,因为此方式使管理变得更方便和容易。 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()
    

使用 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
        }
    }
    
    // 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()
    })
    

使用 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
        }
    }
    
    // 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() 
    })                  
    

自定义存储库

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

    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()
    })
    

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)
    })
    

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)
    })
    

实体

  • 实体:是一个映射到数据库表的类。 你可以通过定义一个新类来创建一个实体,并用@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;
          }
      }
      

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;
        }
    }
    
  • 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;
        }
    }
    

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;
        }
    }
    

列选项

  • 列选项定义实体列的其他选项。 你可以在@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;
          }
      }
      
      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)
      })
      

嵌入实体类

  • 通过使用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;
        }
    }
    
    // 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;
        }
    }
    
  • 这里我们将@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()
    })
    

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

  • 多对一/一对多是指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;
        }
    }
    
    // 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;
        }
    }
    
  • 这里我们将@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()
    })
    

多对多的关系(一)

  • 多对多是一种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;
        }
    }
    
    // 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;
        }
    }
    
  • @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()
    })
    

使用 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表示输出到指定的文件夹
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值