【typeorm】typeorm官方文件querybuilder插入更新刪除部分

業火之理發表於2020-10-20
  • 接上篇

使用 Query Builder 插入

你可以使用QueryBuilder建立INSERT查詢。 例如:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .insert()
  .into(User)
  .values([{ firstName: "Timber", lastName: "Saw" }, { firstName: "Phantom", lastName: "Lancer" }])
  .execute();

就效能而言,這是向資料庫中插入實體的最有效方法。 你也可以通過這種方式執行批量插入。

原始SQL支援

在某些情況下需要執行函式SQL查詢時:

import {getConnection} from "typeorm";

await getConnection()
    .createQueryBuilder()
    .insert()
    .into(User)
    .values({ 
        firstName: "Timber", 
        lastName: () => "CONCAT('S', 'A', 'W')"
    })
    .execute();

此語法不會對值進行轉義,你需要自己處理轉義。

使用 Query Builder 更新

你可以使用QueryBuilder建立UPDATE查詢。 例如:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .update(User)
  .set({ firstName: "Timber", lastName: "Saw" })
  .where("id = :id", { id: 1 })
  .execute();

就效能而言,這是更新資料庫中的實體的最有效方法。

原始SQL支援

在某些情況下需要執行函式SQL查詢時:

typescript import {getConnection} from “typeorm”; await getConnection() .createQueryBuilder() .update(User) .set({ firstName: “Timber”, lastName: “Saw”, age: () => “‘age’ + 1” }) .where(“id = :id”, { id: 1 }) .execute();

此語法不會對值進行轉義,你需要自己處理轉義。

使用 Query Builder 刪除

你可以使用QueryBuilder建立DELETE查詢。 例如:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .delete()
  .from(User)
  .where("id = :id", { id: 1 })
  .execute();

就效能而言,這是刪除資料庫中的實體的最有效方法。

與 Relations 結合

RelationQueryBuilder是QueryBuilder的一種允許你使用關係來查詢的特殊型別。 通過使用你可以在資料庫中將實體彼此繫結,而無需載入任何實體,或者可以輕鬆地載入相關實體。 例如:

例如,我們有一個Post實體,它與Category有一個多對多的關係,叫做categories。 讓我們為這種多對多關係新增一個新 category:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(post)
  .add(category);

這段程式碼相當於:

import { getManager } from "typeorm";

const postRepository = getRepository(Post);
const post = await postRepository.findOne(1, { relations: ["categories"] });
post.categories.push(category);
await postRepository.save(post);

但是這樣使用第一種方式效率更高,因為它執行的運算元量最少,並且繫結資料庫中的實體,這比每次都呼叫save這種笨重的方法簡化了很多。

此外,這種方法的另一個好處是不需要在 pushing 之前載入每個相關實體。 例如,如果你在一個 post 中有一萬個 categories,那麼在此列表中新增新 posts 可能會產生問題,因為執行此操作的標準方法是載入包含所有一萬個 categories 的 post,push 一個新 category 然後儲存。 這將會導致非常高的效能成本,而且基本上不適用於生產環境。 但是,使用RelationQueryBuilder則解決了這個問題。

此外,當進行繫結時,可以不需要使用實體,只需要使用實體 ID 即可。 例如,讓我們在 id 為 1 的 post 中新增 id = 3 的 category:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(1)
  .add(3);

如果你使用了複合主鍵,則必須將它們作為 id 對映傳遞,例如:

import { getConnection } from "typeorm";

await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of({ firstPostId: 1, secondPostId: 3 })
  .add({ firstCategoryId: 2, secondCategoryId: 4 });

也可以按照新增實體的方式刪除實體:

import { getConnection } from "typeorm";

// 此程式碼從給定的post中刪除一個category

await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(post) // 也可以使用post id
  .remove(category); // 也可以只使用category ID

新增和刪除相關實體針對多對多和一對多關係。 對於一對一和多對一關係,請使用set代替:

import { getConnection } from "typeorm";

// 此程式碼set給定post的category
await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(post) // 也可以使用post id
  .set(category); // 也可以只使用category ID

如果要取消設定關係(將其設定為 null),只需將null傳遞給set方法:

import { getConnection } from "typeorm";

// 此程式碼取消設定給定post的category
await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(post) // 也可以使用post id
  .set(null);

除了更新關係外,關係查詢構建器還允許你載入關係實體。 例如,假設在Post實體內部,我們有多對多的categories關係和多對一的user關係,為載入這些關係,你可以使用以下程式碼:

import { getConnection } from "typeorm";

const post = await getConnection().manager.findOne(Post, 1);

post.categories = await getConnection()
  .createQueryBuilder()
  .relation(Post, "categories")
  .of(post) // 也可以使用post id
  .loadMany();

post.author = await getConnection()
  .createQueryBuilder()
  .relation(User, "user")
  .of(post) // 也可以使用post id
  .loadOne();

快取查詢

你可以快取getMany,getOne,getRawMany,getRawOne和getCount這些QueryBuilder方法的查詢結果。

還可以快取find,findAndCount,findByIds和count這些Repository方法查詢的結果。

要啟用快取,需要在連線選項中明確啟用它:

{
    type: "mysql",
    host: "localhost",
    username: "test",
    ...
    cache: true
}

首次啟用快取時,你必須同步資料庫架構(使用 CLI,migrations 或synchronize連線選項)。

然後在QueryBuilder中,你可以為任何查詢啟用查詢快取:

const users = await connection
  .createQueryBuilder(User, "user")
  .where("user.isAdmin = :isAdmin", { isAdmin: true })
  .cache(true)
  .getMany();

等同於Repository查詢:

const users = await connection.getRepository(User).find({
  where: { isAdmin: true },
  cache: true
});

這將執行查詢以獲取所有 admin users 並快取結果。 下次執行相同的程式碼時,它將從快取中獲取所有 admin users。 預設快取生存期為1000 ms,例如 1 秒。 這意味著在呼叫查詢構建器程式碼後 1 秒內快取將無效。 實際上,這也意味著如果使用者在 3 秒內開啟使用者頁面 150 次,則在此期間只會執行三次查詢。 在 1 秒快取視窗期間插入的任何 users 都不會返回到 user。

你可以通過QueryBuilder手動更改快取時間:

const users = await connection
  .createQueryBuilder(User, "user")
  .where("user.isAdmin = :isAdmin", { isAdmin: true })
  .cache(60000) // 1 分鐘
  .getMany();

或者通過 Repository:

const users = await connection.getRepository(User).find({
  where: { isAdmin: true },
  cache: 60000
});

或者通過全域性連線選項:

{
    type: "mysql",
    host: "localhost",
    username: "test",
    ...
    cache: {
        duration: 30000 // 30 seconds
    }
}

此外,你可以通過QueryBuilder設定"cache id":

const users = await connection
  .createQueryBuilder(User, "user")
  .where("user.isAdmin = :isAdmin", { isAdmin: true })
  .cache("users_admins", 25000)
  .getMany();

或者通過 Repository:

const users = await connection.getRepository(User).find({
  where: { isAdmin: true },
  cache: {
    id: "users_admins",
    milisseconds: 25000
  }
});

這使你可以精確控制快取,例如,在插入新使用者時清除快取的結果:

await connection.queryResultCache.remove(["users_admins"]);

預設情況下,TypeORM 使用一個名為query-result-cache的單獨表,並在那裡儲存所有查詢和結果。 表名是可配置的,因此您可以通過在 tableName 屬性中給出值來更改它 例如:

{
    type: "mysql",
    host: "localhost",
    username: "test",
    ...
    cache: {
        type: "database",
        tableName: "configurable-table-query-result-cache"
    }
}

如果在單個資料庫表中儲存快取對你無效,則可以將快取型別更改為"redis"或者"ioredis",而 TypeORM 將以 redis 形式儲存所有快取的記錄。 例如:

{
    type: "mysql",
    host: "localhost",
    username: "test",
    ...
    cache: {
        type: "redis",
        options: {
            host: "localhost",
            port: 6379
        }
    }
}

“options” 可以是node_redis specific options 或者 ioredis specific options,具體取決於你使用的型別。

如果你想使用IORedis的叢集功能連線到redis-cluster,則可以通過方式下操作來執行此操作:


請注意,你仍然可以使用選項作為IORedis的叢集建構函式的第一個引數。
typescript { ... cache: { type: "ioredis/cluster", options: [ { host: 'localhost', port: 7000, }, { host: 'localhost', port: 7001, }, { host: 'localhost', port: 7002, } ] }, ... } ```

你可以使用typeorm cache:clear來清除儲存在快取中的所有內容。

相關文章