• 视图实体
    • 什么是视图实体?
    • 视图实体列
    • 完整示例

    视图实体

    什么是视图实体?

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

    @ViewEntity() 接收以下参数:

    • name - 视图名称。 如果未指定,则从实体类名生成视图名称。
    • database - 所选DB服务器中的数据库名称。
    • schema - 架构名称。
    • expression - 视图定义。 必需参数

    expression可以是带有正确转义的列和表的字符串,取决于所使用的数据库(示例中为postgres):

    1. @ViewEntity({
    2. expression: `
    3. SELECT "post"."id" "id", "post"."name" AS "name", "category"."name" AS "categoryName"
    4. FROM "post" "post"
    5. LEFT JOIN "category" "category" ON "post"."categoryId" = "category"."id"
    6. `
    7. })

    或者是QueryBuilder的一个实例

    1. @ViewEntity({
    2. expression: (connection: Connection) => connection.createQueryBuilder()
    3. .select("post.id", "id")
    4. .addSelect("post.name", "name")
    5. .addSelect("category.name", "categoryName")
    6. .from(Post, "post")
    7. .leftJoin(Category, "category", "category.id = post.categoryId")
    8. })

    注意: 由于驱动程序的限制,不支持参数绑定。请改用文字参数。

    1. @ViewEntity({
    2. expression: (connection: Connection) => connection.createQueryBuilder()
    3. .select("post.id", "id")
    4. .addSelect("post.name", "name")
    5. .addSelect("category.name", "categoryName")
    6. .from(Post, "post")
    7. .leftJoin(Category, "category", "category.id = post.categoryId")
    8. .where("category.name = :name", { name: "Cars" }) // <-- 这是错的
    9. .where("category.name = 'Cars'") // <-- 这是对的
    10. })

    每个视图实体都必须在连接选项中注册:

    1. import {createConnection, Connection} from "typeorm";
    2. import {UserView} from "./entity/UserView";
    3. const connection: Connection = await createConnection({
    4. type: "mysql",
    5. host: "localhost",
    6. port: 3306,
    7. username: "test",
    8. password: "test",
    9. database: "test",
    10. entities: [UserView]
    11. });

    或者你可以指定包含所有实体的整个目录 - 所有实体都将被加载:

    1. import {createConnection, Connection} from "typeorm";
    2. const connection: Connection = await createConnection({
    3. type: "mysql",
    4. host: "localhost",
    5. port: 3306,
    6. username: "test",
    7. password: "test",
    8. database: "test",
    9. entities: ["entity/*.js"]
    10. });

    视图实体列

    要将视图中的数据映射到正确的实体列,必须使用@ViewColumn()装饰器标记实体列,并将这些列指定为select语句别名。

    字符串表达式定义的示例:

    1. import {ViewEntity, ViewColumn} from "typeorm";
    2. @ViewEntity({
    3. expression: `
    4. SELECT "post"."id" AS "id", "post"."name" AS "name", "category"."name" AS "categoryName"
    5. FROM "post" "post"
    6. LEFT JOIN "category" "category" ON "post"."categoryId" = "category"."id"
    7. `
    8. })
    9. export class PostCategory {
    10. @ViewColumn()
    11. id: number;
    12. @ViewColumn()
    13. name: string;
    14. @ViewColumn()
    15. categoryName: string;
    16. }

    使用QueryBuilder的示例:

    1. import {ViewEntity, ViewColumn} from "typeorm";
    2. @ViewEntity({
    3. expression: (connection: Connection) => connection.createQueryBuilder()
    4. .select("post.id", "id")
    5. .addSelect("post.name", "name")
    6. .addSelect("category.name", "categoryName")
    7. .from(Post, "post")
    8. .leftJoin(Category, "category", "category.id = post.categoryId")
    9. })
    10. export class PostCategory {
    11. @ViewColumn()
    12. id: number;
    13. @ViewColumn()
    14. name: string;
    15. @ViewColumn()
    16. categoryName: string;
    17. }

    完整示例

    让我们创建两个实体和一个包含来自这些实体的聚合数据的视图:

    1. import {Entity, PrimaryGeneratedColumn, Column} from "typeorm";
    2. @Entity()
    3. export class Category {
    4. @PrimaryGeneratedColumn()
    5. id: number;
    6. @Column()
    7. name: string;
    8. }
    1. import {Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn} from "typeorm";
    2. import {Category} from "./Category";
    3. @Entity()
    4. export class Post {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. name: string;
    9. @Column()
    10. categoryId: number;
    11. @ManyToOne(() => Category)
    12. @JoinColumn({ name: "categoryId" })
    13. category: Category;
    14. }
    1. import {ViewEntity, ViewColumn} from "typeorm";
    2. @ViewEntity({
    3. expression: (connection: Connection) => connection.createQueryBuilder()
    4. .select("post.id", "id")
    5. .addSelect("post.name", "name")
    6. .addSelect("category.name", "categoryName")
    7. .from(Post, "post")
    8. .leftJoin(Category, "category", "category.id = post.categoryId")
    9. })
    10. export class PostCategory {
    11. @ViewColumn()
    12. id: number;
    13. @ViewColumn()
    14. name: string;
    15. @ViewColumn()
    16. categoryName: string;
    17. }

    然后用数据填充这些表并从PostCategory视图请求所有数据:

    1. import {getManager} from "typeorm";
    2. import {Category} from "./entity/Category";
    3. import {Post} from "./entity/Post";
    4. import {PostCategory} from "./entity/PostCategory";
    5. const entityManager = getManager();
    6. const category1 = new Category();
    7. category1.name = "Cars";
    8. await entityManager.save(category1);
    9. const category2 = new Category();
    10. category2.name = "Airplanes";
    11. await entityManager.save(category2);
    12. const post1 = new Post();
    13. post1.name = "About BMW";
    14. post1.categoryId = category1.id;
    15. await entityManager.save(post1);
    16. const post2 = new Post();
    17. post2.name = "About Boeing";
    18. post2.categoryId = category2.id;
    19. await entityManager.save(post2);
    20. const postCategories = await entityManager.find(PostCategory);
    21. const postCategory = await entityManager.findOne(PostCategory, { id: 1 });

    postCategories的结果将是:

    1. [ PostCategory { id: 1, name: 'About BMW', categoryName: 'Cars' },
    2. PostCategory { id: 2, name: 'About Boeing', categoryName: 'Airplanes' } ]

    postCategory中:

    1. PostCategory { id: 1, name: 'About BMW', categoryName: 'Cars' }