跳至主要内容
版本:v6 - 稳定

命名策略

underscored 选项

Sequelize 为模型提供 underscored 选项。当设置为 true 时,此选项将设置所有属性的 field 选项为其名称的 蛇形命名法 版本。这也适用于关联自动生成的外部键和其他自动生成的字段。示例

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 属性,指向任务表中名为 userId 的列

启用 underscored 选项后,Sequelize 将改为定义

  • 每个模型的 createdAt 属性,指向每个表中名为 created_at 的列
  • 每个模型的 updatedAt 属性,指向每个表中名为 updated_at 的列
  • Task 模型中的 userId 属性,指向任务表中名为 user_id 的列

请注意,在这两种情况下,字段在 JavaScript 端仍然是 驼峰命名法;此选项仅更改这些字段如何映射到数据库本身。每个属性的 field 选项都设置为其蛇形命名法版本,但属性本身仍然是驼峰命名法。

这样,在上述代码上调用 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")
);

单数与复数

乍一看,在 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);

添加到用户实例中的 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' });