typeorm装饰器之Column

src/decorator/columns/Column.ts
import {ColumnOptions} from "../options/ColumnOptions";
import {getMetadataArgsStorage} from "../../index";
import {
    ColumnType,
    SimpleColumnType,
    WithLengthColumnType,
    WithPrecisionColumnType
} from "../../driver/types/ColumnTypes";
import {ColumnMetadataArgs} from "../../metadata-args/ColumnMetadataArgs";
import {ColumnCommonOptions} from "../options/ColumnCommonOptions";
import {ColumnWithLengthOptions} from "../options/ColumnWithLengthOptions";
import {ColumnNumericOptions} from "../options/ColumnNumericOptions";
import {ColumnEnumOptions} from "../options/ColumnEnumOptions";
import {ColumnEmbeddedOptions} from "../options/ColumnEmbeddedOptions";
import {EmbeddedMetadataArgs} from "../../metadata-args/EmbeddedMetadataArgs";

//列装饰工厂声明
export function Column(): Function;

//带有选项的工厂函数声明
export function Column(options: ColumnOptions): Function;

//参数为简单类型与通用列选项
export function Column(type: SimpleColumnType, options?: ColumnCommonOptions): Function;

//参数为带有长度列类型,选项多了长度属性
export function Column(type: WithLengthColumnType, options?: ColumnCommonOptions & ColumnWithLengthOptions): Function;

//参数为带有精度列类型,选项多了精度、标度类型
export function Column(type: WithPrecisionColumnType, options?: ColumnCommonOptions & ColumnNumericOptions): Function;

//枚举类型,选项中多了枚举值数组属性
export function Column(type: "enum", options?: ColumnCommonOptions & ColumnEnumOptions): Function;

//第一个参数为函数,返回值为内嵌类构造函数,第二个参数为内嵌列选项,指定了所有内嵌列的前缀
export function Column(type: (type?: any) => Function, options?: ColumnEmbeddedOptions): Function;

//函数实现
export function Column(typeOrOptions?: ((type?: any) => Function)|ColumnType|(ColumnOptions&ColumnEmbeddedOptions), options?: (ColumnOptions&ColumnEmbeddedOptions)): Function {
    //列类型
    let type: ColumnType|undefined;
    //如果是string类型或者函数类型,Function代表了返回内嵌类构造函数的函数
    if (typeof typeOrOptions === "string" || typeOrOptions instanceof Function) {
        type =  typeOrOptions;
    }
    //如果不是,第一个参数为列选项
    else if (typeOrOptions) {
        options =  typeOrOptions;
        //类型为type属性
        type = typeOrOptions.type;
    }
    //返回装饰器
    return function (object: Object, propertyName: string) {
        //如果为函数,代表了内嵌对象列
        if (typeOrOptions instanceof Function) {
            //内嵌类型
            const reflectMetadataType = Reflect && (Reflect as any).getMetadata ? (Reflect as any).getMetadata("design:type", object, propertyName) : undefined;
            //内嵌类是否为数组
            const isArray = reflectMetadataType === Array || (options && (options.isArray === true || options.array === true)) ? true : false;
            //内嵌类元数据参数
            const args: EmbeddedMetadataArgs = {
                //实体构造函数
                target: object.constructor,
                //属性名
                propertyName: propertyName,
                //内嵌类是否为数组
                isArray: isArray,
                //内嵌列前缀
                prefix: options && options.prefix !== undefined ? options.prefix : undefined,
                //返回内嵌类构造函数的方法
                type: typeOrOptions as (type?: any) => Function
            };
            //添加内嵌类元数据
            getMetadataArgsStorage().embeddeds.push(args);

        } 
        //为正常列类
        else {
            //如果既没有直接在参数中指定列类型,又没有在选项中指定列类型,获取实体中列属性声明的类型
            if (!type) {
                const reflectMetadataType = Reflect && (Reflect as any).getMetadata ? (Reflect as any).getMetadata("design:type", object, propertyName) : undefined;
                if (reflectMetadataType)
                    type = reflectMetadataType; // todo: need to determine later on driver level
            }
            //列选项最次为空对象
            if (!options) options = {} as ColumnOptions;
            //将type合并到选项的type属性
            if (!options.type && type)
                options = Object.assign({ type: type } as ColumnOptions, options);
            //列元数据参数
            const args: ColumnMetadataArgs = {
                //构造函数
                target: object.constructor,
                //列属性名
                propertyName: propertyName,
                //模式
                mode: "regular",
                //列选项
                options: options
            };
            getMetadataArgsStorage().columns.push(args);
        }
    };
}

可以看到装饰器有几种参数情况:

1.无参数,默认采用属性名为列名

测试:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn("integer")
    id: number;
    @Column()
    nameDDDDD:string
}
表结构:

-----------+
| Table | Create Table                                                                                                                                    |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (  `id` int(11) NOT NULL,
  `nameDDDDD` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+


2.只有列选项
src/decorator/options/ColumnOptions.ts
import {ColumnType} from "../../driver/types/ColumnTypes";
import {ValueTransformer} from "./ValueTransformer";
//列选项接口
export interface ColumnOptions {
    //列类型
    type?: ColumnType;
    //列名
    name?: string;
    //某些列类型带有长度参数,如string->varchar
    length?: string|number;
    //是否可以为空
    nullable?: boolean;
    //列是否只读,true意味着只有第一次插入表数据时可以初始化这个列值,不可更新它
    readonly?: boolean;
    //指明列是否总是被QueryBuilder和find操作选择,默认值为true
    select?: boolean;
    //列默认值
    default?: any;
    //指明列是否是主键列
    //与@PrimaryColumn装饰器作用一样
    primary?: boolean;
    //列值在数据库中是否唯一
    unique?: boolean;
    //列注解,目前不支持
    comment?: string;
    //精度
    precision?: number;
    //标度,只有某些类支持
    scale?: number;
    //列字符集,目前不支持
    charset?: string;
    //列校对
    collation?: string;
    //对枚举类型,指定枚举值数组
    enum?: any[]|Object;
    //列是否为数组,只有postgres支持
    isArray?: boolean;
    //列是否为数组,只有postgres支持
    array?: boolean;
    //指定一个值转换器,用于读写数据库时对列值进行读写
    transformer?: ValueTransformer;   
}
测试1:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn("integer")
    id: number;
    @Column({
        type:'varchar',
        name:'nameAAAA',
        length:50,
        nullable:false,
        unique:true,
        default:'dazhentan'
    })
    nameDDDDD:string;
}
表结构:

| Table | Create Table
                                    |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `nameAAAA` varchar(50) NOT NULL DEFAULT 'dazhentan',
  PRIMARY KEY (`id`),
  UNIQUE KEY `nameAAAA` (`nameAAAA`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
可以看到type、name、length、nullable、unique、default属性的作用

测试2:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @Column({
        primary:true,
    })
    id: number;
}
表结构:

+-------+------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                               |
+-------+------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+------------------------------------------------------------------------------------------------------------+
可以看到primary为true,相当于PrimaryColumn装饰器,但是注意这种方式并不能设置generated属性,即不能指定自动生成主键


3.参数一为简单类型,参数二为通用选项

import {ValueTransformer} from "./ValueTransformer";
//所有列类型通用的列选项
//Column装饰器通用选项接口
export interface ColumnCommonOptions {
    //列是否被QueryBuilder与find操作默认选择,即执行查询时这个列数据是否默认被选择
    select?: boolean;
    //列名
    name?: string;
    //是否为主键列,与@PrimaryColumn装饰器作用一样
    primary?: boolean;
    //列值是否自动生成,只有primary为true时起作用,也就是只有主键列可以自动生成
    generated?: boolean;
    //列值是否唯一,会对表添加唯一性约束
    unique?: boolean;
    //列值是否可为空
    nullable?: boolean;
    //默认值
    default?: any;
    //列注解,目前不支持
    comment?: string;
    //是否为数组列,只有postgres支持
    isArray?: boolean;
    //指定一个值转换器,当向数据库读写数据时对数据进行转换
    transformer?: ValueTransformer;
}
可以看到,通用选项中没有type、length、readonly、pricision、scale、enum等属性,这些属性都放在了单独接口中(除了readonly外),但是多了一个generated属性,即可以设置自动生成主键列
测试1:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn()
    id: number;
    @Column('year',{
        name:'yeareDDDD',
        unique:true,
        nullable:false,
        default:1980
    })
    yearAAAA:string;
}
表结构:

| Table | Create Table
                              |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `yeareDDDD` year(4) NOT NULL DEFAULT '1980',
  PRIMARY KEY (`id`),
  UNIQUE KEY `yeareDDDD` (`yeareDDDD`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
注意简单类型,不包含varchar类型,是year来测试


4.参数一为带长度列类型,参数二为通用选项加上length属性

src/decorator/options/ColumnWithLengthOptions.ts
//带有长度的列选项
export interface ColumnWithLengthOptions {
    //长度值,数字字符串或者数字
    length?: string|number;
}

测试一:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn()
    id:number;
    @Column('varchar',{
        length:20
    })
    name:string;
}

表结构:

+-------+-------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                              |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------+

测试二:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @Column('int',{
        primary:true,
        generated:true
    })
    id:number;
}

表结构:

+-------+------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                               |
+-------+------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+------------------------------------------------------------------------------------------------------------+
很尴尬,generated属性没有预期作用

5.参数一位带精度列类型,参数二为通用选项加上precision、scale属性

src/decorator/options/ColumnNumericOptions.ts
//带有精度列类型选项
export interface ColumnNumericOptions {
    //精度
    precision?: number;
    //标度
    scale?: number;
}

测试:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn()
    id:number;
    @Column('decimal',{
        precision:8,
        scale:2
    })
    name:number;
}
表结构:

+-------+--------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                               |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `name` decimal(8,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------+

6.参数一为enum,参数二为通用选项加上枚举值数组属性

src/decoratoc/options/ColumnEnumOptions.ts
//枚举类型列选项
export interface ColumnEnumOptions {
    //枚举值数组
    enum?: any[]|Object;
}
测试:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";
@Entity()
export class Post {
    @PrimaryColumn()
    id:number;
    @Column('enum',{
        enum:['A','B','C']
    })
    name:string;
}
表结构:

+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                    |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `name` enum('A','B','C') NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
mysql中由enum类型,括号里面为枚举值,枚举值在数据库中存储都是使用字符串类型

7.参数一为函数,返回内嵌类构造函数,参数二为通用选项加上内嵌类的列前缀

src/decoratoc/options/ColumnEmbeddedOptions.ts
//内嵌列类型选项
export interface ColumnEmbeddedOptions {
    //内嵌列前缀
    prefix?: string;
}

测试:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";

class Embed{
    @Column()
    firstname:string;
    @Column()
    lastname:string;
}
@Entity()
export class Post {
    @PrimaryColumn()
    id:number;
    @Column(type=>Embed,{
        prefix:'embed'
    })
    embed:Embed;
}
表结构:

| Table | Create Table
                          |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `embedFirstname` varchar(255) NOT NULL,
  `embedLastname` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
可以看到,内嵌类属性必须使用列注解,最后的列名为prefix前缀加上原有内嵌列属性名首字母大写

最后还有一个simple-array类型,这个类型是可以将数组类型属性,存储为数据库中的文本类型,转换由typeorm内部自动进行

测试:

import {Column, Entity} from "../../../src/index";
import {PrimaryColumn} from "../../../src/decorator/columns/PrimaryColumn";
import {Generated} from "../../../src/decorator/Generated";


@Entity()
export class Post {
    @PrimaryColumn()
    id:number;
    @Column('simple-array')
    array:string[];
}
import "reflect-metadata";
import {ConnectionOptions, createConnection} from "../../src/index";
import {Post} from "./entity/Post";

const options: ConnectionOptions = {
    "name": "mysql",
    "type": "mysql",
    "host": "localhost",
    "port": 3306,
    "username": "root",
    "password": "123456",
    "database": "test",
    synchronize: true,
    entities: [Post]
};
createConnection(options).then(async connection => {
    let  post = new Post()
    post.id = 1
    post.array = ['AAA','BBB','CCC']
    connection.getRepository(Post).save(post)
}, error => console.log("Cannot connect: ", error));
表结构:

+-------+-------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                        |
+-------+-------------------------------------------------------------------------------------------------------------------------------------+
| post  | CREATE TABLE `post` (
  `id` int(11) NOT NULL,
  `array` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------------------------------------------------+
表数据:

+----+-------------+
| id | array       |
+----+-------------+
|  1 | AAA,BBB,CCC |
+----+-------------+
可见,typeorm将simple-array类型的数组属性存储为mysql中的text类型,存储值为数组元素用逗号拼接起来,从数据库中查询array属性,会直接得到数组













你可能感兴趣的:(typeorm)