跳到主要內容

原型化您的 Schema

Prisma CLI 有一個專門用於原型化 schema 的指令:db push

db push 使用與 Prisma Migrate 相同的引擎,將您的 Prisma schema 與您的資料庫 schema 同步。 db push 指令

  1. 內省資料庫以推斷並執行必要的變更,使您的資料庫 schema 反映您的 Prisma schema 的狀態。

  2. 預設情況下,在變更套用至資料庫 schema 後,會觸發產生器 (例如 Prisma Client)。您不需要手動調用 prisma generate

  3. 如果 db push 預期變更可能會導致資料遺失,它將會

    • 拋出錯誤
    • 如果您仍然想要進行變更,則需要 --accept-data-loss 選項

注意事項:

  • db push 不會與 migration 互動或依賴 migration。migration 表格 _prisma_migrations 不會被建立或更新,也不會產生任何 migration 檔案。
  • 當使用 PlanetScale 時,我們建議您使用 db push 而不是 migrate。如需詳細資訊,請參閱我們的「開始使用」文件,根據您的情況,請參閱從頭開始新增至現有專案

選擇 db push 或 Prisma Migrate

在以下情況下,db push 運作良好

  • 您想要在本地快速原型化和迭代 schema 設計,而無需將這些變更部署到其他環境,例如其他開發人員,或預備和生產環境。
  • 您優先考慮達到期望的最終狀態,而不是為達到該最終狀態而執行的變更或步驟 (無法預覽 db push 所做的變更)
  • 您不需要控制 schema 變更如何影響資料。無法協調 schema 和資料 migration — 如果 db push 預期變更將導致資料遺失,您可以接受使用 --accept-data-loss 選項遺失資料,或停止該程序。 無法自訂變更。

請參閱使用 db push 進行 Schema 原型化,以取得如何以這種方式使用 db push 的範例。

在以下情況下,不建議使用 db push

  • 您想要在不遺失資料的情況下,在其他環境中複製您的 schema 變更。 您可以使用 db push 進行原型化,但您應該使用 migration 來提交 schema 變更,並在您的其他環境中套用這些變更。
  • 您想要精細控制 schema 變更的執行方式 - 例如,重新命名欄位而不是刪除它並建立一個新欄位
  • 您想要追蹤一段時間內對資料庫 schema 所做的變更。 db push 不會建立任何構件,讓您可以追蹤這些變更。
  • 您希望 schema 變更是可逆的。您可以再次使用 db push 還原到原始狀態,但這可能會導致資料遺失。

我可以同時使用 Prisma Migrate 和 db push 嗎?

是的,您可以在您的開發工作流程中一起使用 db push 和 Prisma Migrate。 例如,您可以

  • 在專案開始時使用 db push 原型化 schema,並在您對第一個草稿感到滿意時初始化 migration 歷史記錄
  • 使用 db push 原型化對現有 schema 的變更,然後執行 prisma migrate dev 從您的變更產生 migration (系統會要求您重置)

原型化新的 Schema

以下情境示範如何使用 db push 將新的 schema 與空的資料庫同步,並演進該 schema - 包括當 db push 偵測到變更將導致資料遺失時會發生什麼事。

  1. 建立您的 schema 的第一個草稿

    generator client {
    provider = "prisma-client-js"
    }

    datasource db {
    provider = "postgresql"
    url = env("DATABASE_URL")
    }

    model User {
    id Int @id @default(autoincrement())
    name String
    jobTitle String
    posts Post[]
    profile Profile?
    }

    model Profile {
    id Int @id @default(autoincrement())
    biograpy String // Intentional typo!
    userId Int @unique
    user User @relation(fields: [userId], references: [id])
    }

    model Post {
    id Int @id @default(autoincrement())
    title String
    published Boolean @default(true)
    content String @db.VarChar(500)
    authorId Int
    author User @relation(fields: [authorId], references: [id])
    categories Category[]
    }

    model Category {
    id Int @id @default(autoincrement())
    name String @db.VarChar(50)
    posts Post[]

    @@unique([name])
    }
  2. 使用 db push 將初始 schema 推送到資料庫

    npx prisma db push
  3. 建立一些範例內容

    const add = await prisma.user.create({
    data: {
    name: 'Eloise',
    jobTitle: 'Programmer',
    posts: {
    create: {
    title: 'How to create a MySQL database',
    content: 'Some content',
    },
    },
    },
    })
  4. 進行附加變更 - 例如,建立新的必要欄位

    // ... //

    model Post {
    id Int @id @default(autoincrement())
    title String
    description String
    published Boolean @default(true)
    content String @db.VarChar(500)
    authorId Int
    author User @relation(fields: [authorId], references: [id])
    categories Category[]
    }

    // ... //
  5. 推送變更

    npx prisma db push

    db push 將提示您重置,因為您無法將必要欄位新增到具有現有內容的表格,除非您提供預設值

    ⚠️ We found changes that cannot be executed:

    • Added the required column `description` to the `Post` table without a default value. There are 2 rows in this table, it is not possible to execute this.

    ? To apply this step we need to reset the database, do you want to continue? All data will be lost. » (y/N)
提示

使用 --accept-data-loss 標記以略過此警告,或使用 --force-reset 忽略所有警告。

  1. 確認資料遺失並將變更套用至您的資料庫 (或重新檢視您的 schema)

     There might be data loss when applying the changes:

    • Added the required column `description` to the `Post` table without a default value.

    ? Do you want to ignore the warning(s)? Some data will be lost. » (y/N)

    注意:與 Prisma Migrate 不同,db push 不會產生您可以修改以保留資料的 migration,因此最適合在開發環境中進行原型化。

  2. 繼續演進您的 schema,直到它達到相對穩定的狀態。

  3. 初始化 migration 歷史記錄

    npx prisma migrate dev --name initial-state

    達到初始原型的步驟未被保留 - db push 不會產生歷史記錄。

  4. 將您的 migration 歷史記錄和 Prisma schema 推送到原始碼控制 (例如 Git)。

此時,您的原型化的最終草稿會保留在 migration 中,並且可以推送到其他環境 (測試、生產環境或您團隊的其他成員)。

使用現有 migration 歷史記錄進行原型化

以下情境示範如何使用 db push 原型化對 Prisma schema 的變更,其中已存在 migration 歷史記錄。

  1. 檢查最新的 Prisma schema 和 migration 歷史記錄

    generator client {
    provider = "prisma-client-js"
    }

    datasource db {
    provider = "postgresql"
    url = env("DATABASE_URL")
    }

    model User {
    id Int @id @default(autoincrement())
    name String
    jobTitle String
    posts Post[]
    profile Profile?
    }

    model Profile {
    id Int @id @default(autoincrement())
    biograpy String // Intentional typo!
    userId Int @unique
    user User @relation(fields: [userId], references: [id])
    }

    model Post {
    id Int @id @default(autoincrement())
    title String
    published Boolean @default(true)
    content String @db.VarChar(500)
    authorId Int
    author User @relation(fields: [authorId], references: [id])
    categories Category[]
    }

    model Category {
    id Int @id @default(autoincrement())
    name String @db.VarChar(50)
    posts Post[]

    @@unique([name])
    }
  2. 原型化您的新功能,其中可能包含任意數量的步驟。 例如,您可能會

    • 建立 tags String[] 欄位,然後執行 db push
    • 將欄位類型變更為 tags Tag[] 並新增名為 Tag 的新模型,然後執行 db push
    • 改變主意並還原原始的 tags String[] 欄位,然後調用 db push
    • 手動變更資料庫中的 tags 欄位 - 例如,新增約束

    在嘗試幾種解決方案後,最終的 schema 變更如下所示

    model Post {
    id Int @id @default(autoincrement())
    title String
    description String
    published Boolean @default(true)
    content String @db.VarChar(500)
    authorId Int
    author User @relation(fields: [authorId], references: [id])
    categories Category[]
    tags String[]
    }
  3. 若要建立新增 tags 欄位的 migration,請執行 migrate dev 指令

    npx prisma migrate dev --name added-tags

    Prisma Migrate 會提示您重置,因為您在原型化時手動和使用 db push 所做的變更不屬於 migration 歷史記錄的一部分

    √ Drift detected: Your database schema is not in sync with your migration history.

    We need to reset the PostgreSQL database "prototyping" at "localhost:5432".
    Do you want to continue? All data will be lost. ... yes
  4. Prisma Migrate 會重播現有的 migration 歷史記錄,根據您的 schema 變更產生新的 migration,並將這些變更套用至資料庫。

提示

當使用 migrate dev 時,如果您的 schema 變更表示種子指令碼將不再運作,您可以使用 --skip-seed 標記來忽略種子指令碼。

此時,您的原型化的最終結果會保留在 migration 中,並且可以推送到其他環境 (測試、生產環境或您團隊的其他成員)。