跳至主要內容
版本:v6 - 穩定版

命名策略

underscored 選項

Sequelize 為模型提供 underscored 選項。當設為 true 時,此選項會將所有屬性的 field 選項設定為其名稱的 snake_case 版本。這也適用於由關聯自動產生的外鍵和其他自動產生的欄位。範例

const User = sequelize.define(
'user',
{ username: Sequelize.STRING },
{
underscored: true,
},
);
const Task = sequelize.define(
'task',
{ title: Sequelize.STRING },
{
underscored: true,
},
);
User.hasMany(Task);
Task.belongsTo(User);

上面我們有 User 和 Task 模型,兩者都使用 underscored 選項。我們還有它們之間的一對多關係。此外,回想一下,由於 timestamps 預設為 true,我們應該預期 createdAtupdatedAt 欄位也會被自動建立。

如果沒有 underscored 選項,Sequelize 會自動定義

  • 每個模型的 createdAt 屬性,指向每個表格中名為 createdAt 的欄位
  • 每個模型的 updatedAt 屬性,指向每個表格中名為 updatedAt 的欄位
  • Task 模型中的 userId 屬性,指向 task 表格中名為 userId 的欄位

啟用 underscored 選項後,Sequelize 將改為定義

  • 每個模型的 createdAt 屬性,指向每個表格中名為 created_at 的欄位
  • 每個模型的 updatedAt 屬性,指向每個表格中名為 updated_at 的欄位
  • Task 模型中的 userId 屬性,指向 task 表格中名為 user_id 的欄位

請注意,在這兩種情況下,欄位在 JavaScript 端仍然是 camelCase;此選項僅更改這些欄位如何對應到資料庫本身。每個屬性的 field 選項都設定為其 snake_case 版本,但屬性本身仍然是 camelCase。

這樣,在上述程式碼上呼叫 sync() 將產生以下結果

CREATE TABLE IF NOT EXISTS "users" (
"id" SERIAL,
"username" VARCHAR(255),
"created_at" TIMESTAMP WITH TIME ZONE NOT NULL,
"updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,
PRIMARY KEY ("id")
);
CREATE TABLE IF NOT EXISTS "tasks" (
"id" SERIAL,
"title" VARCHAR(255),
"created_at" TIMESTAMP WITH TIME ZONE NOT NULL,
"updated_at" TIMESTAMP WITH TIME ZONE NOT NULL,
"user_id" INTEGER REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
PRIMARY KEY ("id")
);

單數 vs. 複數

乍看之下,可能會混淆在 Sequelize 中應該使用名稱的單數形式還是複數形式。本節旨在釐清這一點。

回想一下,Sequelize 在底層使用一個名為 inflection 的程式庫,以便正確計算不規則複數(例如 person -> people)。但是,如果您使用其他語言,您可能需要直接定義名稱的單數和複數形式;sequelize 允許您使用一些選項來執行此操作。

定義模型時

模型應該使用單數字詞形式定義。範例

sequelize.define('foo', { name: DataTypes.STRING });

上面,模型名稱是 foo (單數),而相應的表格名稱是 foos,因為 Sequelize 會自動取得表格名稱的複數形式。

在模型中定義參考鍵時

sequelize.define('foo', {
name: DataTypes.STRING,
barId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'bars',
key: 'id',
},
onDelete: 'CASCADE',
},
});

在上面的範例中,我們手動定義一個參考另一個模型的鍵。這並不常見,但如果您必須這樣做,您應該在那裡使用表格名稱。這是因為參考是根據被參考的表格名稱建立的。在上面的範例中,使用了複數形式(bars),假設 bar 模型是在預設設定下建立的(使其底層表格自動複數化)。

從預先載入中檢索資料時

當您在查詢中執行 include 時,包含的資料將會根據以下規則新增至傳回物件的額外欄位

  • 當從單一關聯(hasOnebelongsTo)包含某些內容時 - 欄位名稱將是模型名稱的單數版本;
  • 當從多重關聯(hasManybelongsToMany)包含某些內容時 - 欄位名稱將是模型的複數形式。

簡而言之,欄位名稱將在每種情況下採用最合乎邏輯的形式。

範例

// Assuming Foo.hasMany(Bar)
const foo = Foo.findOne({ include: Bar });
// foo.bars will be an array
// foo.bar will not exist since it doens't make sense

// Assuming Foo.hasOne(Bar)
const foo = Foo.findOne({ include: Bar });
// foo.bar will be an object (possibly null if there is no associated model)
// foo.bars will not exist since it doens't make sense

// And so on.

在定義別名時覆寫單數和複數

當為關聯定義別名時,您可以傳遞一個物件來指定單數和複數形式,而不是僅使用 { as: 'myAlias' }

Project.belongsToMany(User, {
as: {
singular: 'líder',
plural: 'líderes',
},
});

如果您知道模型在關聯中總是使用相同的別名,您可以直接向模型本身提供單數和複數形式

const User = sequelize.define(
'user',
{
/* ... */
},
{
name: {
singular: 'líder',
plural: 'líderes',
},
},
);
Project.belongsToMany(User);

新增到 user 實例的 mixin 將使用正確的形式。例如,Sequelize 將提供 project.getLíder(),而不是 project.addUser()。此外,Sequelize 將提供 project.setLíderes(),而不是 project.setUsers()

注意:回想一下,使用 as 來更改關聯的名稱也會更改外鍵的名稱。因此,建議在這種情況下也直接指定所涉及的外鍵。

// Example of possible mistake
Invoice.belongsTo(Subscription, { as: 'TheSubscription' });
Subscription.hasMany(Invoice);

上面的第一個呼叫將在 Invoice 上建立一個名為 theSubscriptionId 的外鍵。但是,第二個呼叫也會在 Invoice 上建立一個外鍵(因為我們知道,hasMany 呼叫將外鍵放置在目標模型中) - 但是,它將被命名為 subscriptionId。這樣您將同時擁有 subscriptionIdtheSubscriptionId 欄位。

最好的方法是為外鍵選擇一個名稱,並將其明確地放置在兩個呼叫中。例如,如果選擇了 subscription_id

// Fixed example
Invoice.belongsTo(Subscription, {
as: 'TheSubscription',
foreignKey: 'subscription_id',
});
Subscription.hasMany(Invoice, { foreignKey: 'subscription_id' });