目錄
columns
entity的column對應的就是table的column,定義方式有裝飾器(下方使用)、schema 2種
entity column
- @Column
- 對應table中的一般column
primary columns
primary column是被設為primary key的column,
每個entity都至少
有一個
primary column-- 幫已存在的column新增約束 -- uniqueLibraryName是約束的名稱,可隨意取 ALTER TABLE libraries ADD CONSTRAINT uniqueLibraryName PRIMARY (name);
@PrimaryColumn()
- primary key的column
- @PrimaryGeneratedColumn()
- primary key + auto-increment的column
special column
@CreateDateColumn、@UpdateDateColumn、@DeleteDateColumn
自動記錄時間
的新增、編輯、刪除的column對應下圖的createdAt和updatedAt
-- 幫已經存在的table新增column ALTER books ADD COLUMN createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ADD COLUMN updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
操作起來會像這樣
Automatic Initialization and Updating for TIMESTAMP and DATETIME
How to add 'created_at' and 'updated_at' columns?
enum column
MySQL支援enum column,可以用在狀態、類型這類有選項的地方
當試著新增一筆資料時,若enum column輸入的值不在enum內,就會得到"Data truncated for column '欄位名城' at row n"的報錯
-- 修改已存在的column型別為enum
ALTER TABLE books
MODIFY status ENUM('ready', 'renting', 'missing');
@Column("enum", {
name: "status",
nullable: true,
enum: ["ready", "renting", "missing"],
})
status: "ready" | "renting" | "missing" | null;
其他還有spatial column(記錄位置資料)、set column(MySQL不支援)、simple-json(在前一篇示範過了,JSON column就是垃圾)之類的,但就不多介紹了
entity繼承 & 嵌入entity
這兩種方式都可以減少重複的column,但還是不一樣
繼承用在column名稱完全不一樣時(ex: name, phone),嵌入則用在前綴一樣時(ex: nameFirst, nameLast)
繼承
假設publisher、user都有phone、name這兩個欄位
先建立一個擁有共同的column的class
export abstract class FixedInfo {
@Column("varchar", { name: "name", length: 100 })
name: string;
@Column("varchar", { name: "phone", nullable: true, length: 10 })
phone: string | null;
}
然後extends
@Entity("publishers", { schema: "bookInfos" })
export class Publishers {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
@OneToMany(() => Books, (books) => books.publisher)
books: Books[];
}
export class Users extends FixedInfo {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
@Column("int", { name: "neglect", default: () => "'0'" })
neglect: number;
@OneToMany(() => Books, (books) => books.rentTo2)
books: Books[];
}
嵌入
先建立一個擁有共同的column的class
export abstract class FixedInfo {
@Column("varchar", { name: "name", length: 100 })
name: string;
@Column("varchar", { name: "phone", nullable: true, length: 10 })
phone: string | null;
}
然後connect
注意,如果column名完全不一樣
,千萬不要用
這個方式,不只得不到要的資料,還會把
你的table搞得一團亂
如果只是前綴不一樣記得要設定 {prefix:false},設定完後這個column會被當成是底下有name和phone
import { FixedInfo } from "./FixedInfo"
export class Users {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
// 有設定prefix: false的話,就會當成是name這個欄位底下有name和phone
@Column(() => FixedInfo, {prefix:false})
name: FixedInfo;
@Column("int", { name: "neglect", default: () => "'0'" })
neglect: number;
@OneToMany(() => Books, (books) => books.rentTo2)
books: Books[];
}
view & view entity
view
view
是MySQL query的結果
(檢視表),長得就像table,但
並不
真的存在於資料庫
真的存在資料庫的是Materialized View。它可以用來做暫存,但到目前的MySQL 8.0都不支援(雖然有方法可以做出類似的效果)
使用view的優點如下
簡化查詢複雜度,
加快開發速度
(ex: 每週都會撈每個圖書館的借閱統計,只要做好view就不用每次都打重複的sql語法了)CREATE VIEW view AS (SELECT books.id, books.name FROM books);
加強資料庫的安全性(可以根據不同權限給予看到的view)
資料表變更結構時只需更改 view 的語法
ALTER VIEW view (id, bookName, price) AS (SELECT id, name, price FROM books ORDER BY price DESC);
但是view也是有缺點的
不是所有view都可以update
。涉及多個table、有子查詢、有用到聚合函數、distinct、group、having、union的都無法update,因為它們屬於TEMPTABLE演算法
- TEMPTABLE演算法是建立view時的三個可選演算法之一,預設是UNDEFINED。當設為UNDEFINED時MySQL會自己選要用TEMPTABLE或MERGE
- view本身沒有資料,因此所有
對view進行資料操作
,都會體現在原table中
,所以千萬不要隨意update view
view entity
view entity是一個class,它對應DB的view,當DB裏沒有對應的view,就會自己建立一個
可以直接寫SQL語法
@ViewEntity({
expression: `
SELECT "post"."id" AS "id", "post"."name" AS "name", "category"."name" AS "categoryName"
FROM "post" "post"
LEFT JOIN "category" "category" ON "post"."categoryId" = "category"."id"
`
})
也可以使用TypeORM的抽象工具
@ViewEntity({
expression: (dataSource: DataSource) => dataSource
.createQueryBuilder()
.select("post.id", "id")
.addSelect("post.name", "name")
.addSelect("category.name", "categoryName")
.from(Post, "post")
.leftJoin(Category, "category", "category.id = post.categoryId")
})
但是TypeORM是無法直接query view的
How to query a view instead of a table?
參考資料
Embedded Entities
Entity Inheritance
提升服務效能、減輕DB負擔!(2): Materialized View
View 視圖