Skip to main content
Version: v6 - stable

命名策略

underscored 选项

¥The underscored option

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

¥Sequelize provides the underscored option for a model. When true, this option will set the field option on all attributes to the snake_case version of its name. This also applies to foreign keys automatically generated by associations and other automatically generated fields. Example:

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 字段也会自动创建。

¥Above we have the models User and Task, both using the underscored option. We also have a One-to-Many relationship between them. Also, recall that since timestamps is true by default, we should expect the createdAt and updatedAt fields to be automatically created as well.

如果没有 underscored 选项,Sequelize 将自动定义:

¥Without the underscored option, Sequelize would automatically define:

  • 每个模型都有一个 createdAt 属性,指向每个表中名为 createdAt 的列

    ¥A createdAt attribute for each model, pointing to a column named createdAt in each table

  • 每个模型都有一个 updatedAt 属性,指向每个表中名为 updatedAt 的列

    ¥An updatedAt attribute for each model, pointing to a column named updatedAt in each table

  • Task 模型中的 userId 属性,指向任务表中名为 userId 的列

    ¥A userId attribute in the Task model, pointing to a column named userId in the task table

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

¥With the underscored option enabled, Sequelize will instead define:

  • 每个模型都有一个 createdAt 属性,指向每个表中名为 created_at 的列

    ¥A createdAt attribute for each model, pointing to a column named created_at in each table

  • 每个模型都有一个 updatedAt 属性,指向每个表中名为 updated_at 的列

    ¥An updatedAt attribute for each model, pointing to a column named updated_at in each table

  • Task 模型中的 userId 属性,指向任务表中名为 user_id 的列

    ¥A userId attribute in the Task model, pointing to a column named user_id in the task table

请注意,在这两种情况下,JavaScript 端的字段仍然是 camelCase;此选项仅更改这些字段映射到数据库本身的方式。每个属性的 field 选项都设置为它们的 Snake_case 版本,但属性本身仍然保持 CamelCase。

¥Note that in both cases the fields are still camelCase in the JavaScript side; this option only changes how these fields are mapped to the database itself. The field option of every attribute is set to their snake_case version, but the attribute itself remains camelCase.

这样,在上面的代码上调用 sync() 将生成以下内容:

¥This way, calling sync() on the above code will generate the following:

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")
);

单数与复数

¥Singular vs. Plural

乍一看,Sequelize 中是否应使用名称的单数形式或复数形式可能会令人困惑。本节旨在澄清这一点。

¥At a first glance, it can be confusing whether the singular form or plural form of a name shall be used around in Sequelize. This section aims at clarifying that a bit.

回想一下,Sequelize 在底层使用了一个名为 inflection 的库,以便正确计算不规则复数(例如 person -> people)。但是,如果你使用另一种语言,你可能需要直接定义名称的单数和复数形式;Sequelize 允许你通过一些选项来做到这一点。

¥Recall that Sequelize uses a library called inflection under the hood, so that irregular plurals (such as person -> people) are computed correctly. However, if you're working in another language, you may want to define the singular and plural forms of names directly; sequelize allows you to do this with some options.

定义模型时

¥When defining models

模型应该用单词的单数形式来定义。示例:

¥Models should be defined with the singular form of a word. Example:

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

上面,模型名称为 foo(单数),相应的表名称为 foos,因为 Sequelize 自动获取表名称的复数。

¥Above, the model name is foo (singular), and the respective table name is foos, since Sequelize automatically gets the plural for the table name.

在模型中定义参考键时

¥When defining a reference key in a model

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

在上面的示例中,我们手动定义引用另一个模型的键。通常不这样做,但如果必须这样做,你应该在那里使用表名。这是因为引用是根据引用的表名称创建的。在上面的示例中,使用了复数形式 (bars),假设 bar 模型是使用默认设置创建的(使其基础表自动复数)。

¥In the above example we are manually defining a key that references another model. It's not usual to do this, but if you have to, you should use the table name there. This is because the reference is created upon the referenced table name. In the example above, the plural form was used (bars), assuming that the bar model was created with the default settings (making its underlying table automatically pluralized).

从预加载中检索数据时

¥When retrieving data from eager loading

当你在查询中执行 include 时,包含的数据将根据以下规则添加到返回对象中的额外字段中:

¥When you perform an include in a query, the included data will be added to an extra field in the returned objects, according to the following rules:

  • 当包含来自单个关联(hasOnebelongsTo)的内容时 - 字段名称将是模型名称的单数版本;

    ¥When including something from a single association (hasOne or belongsTo) - the field name will be the singular version of the model name;

  • 当包含来自多重关联(hasManybelongsToMany)的内容时 - 字段名称将是模型的复数形式。

    ¥When including something from a multiple association (hasMany or belongsToMany) - the field name will be the plural form of the model.

简而言之,字段名称将在每种情况下采用最合乎逻辑的形式。

¥In short, the name of the field will take the most logical form in each situation.

示例:

¥Examples:

// 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.

定义别名时覆盖单数和复数

¥Overriding singulars and plurals when defining aliases

为关联定义别名时,你可以传递一个对象来指定单数和复数形式,而不是简单地使用 { as: 'myAlias' }

¥When defining an alias for an association, instead of using simply { as: 'myAlias' }, you can pass an object to specify the singular and plural forms:

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

如果你知道模型将始终在关联中使用相同的别名,则可以直接向模型本身提供单数和复数形式:

¥If you know that a model will always use the same alias in associations, you can provide the singular and plural forms directly to the model itself:

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

添加到用户实例的 mixins 将使用正确的形式。例如,Sequelize 将提供 project.getLíder(),而不是 project.addUser()。此外,Sequelize 将提供 project.setLíderes(),而不是 project.setUsers()

¥The mixins added to the user instances will use the correct forms. For example, instead of project.addUser(), Sequelize will provide project.getLíder(). Also, instead of project.setUsers(), Sequelize will provide project.setLíderes().

注意:回想一下,使用 as 更改关联的名称也会更改外键的名称。因此,建议还指定在这种情况下直接涉及的外键。

¥Note: recall that using as to change the name of the association will also change the name of the foreign key. Therefore it is recommended to also specify the foreign key(s) involved directly in this case.

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

上面的第一个调用将在 Invoice 上建立一个名为 theSubscriptionId 的外键。但是,第二次调用还将在 Invoice 上建立外键(因为据我们所知,hasMany 调用将外键放置在目标模型中) - 不过,它将被命名为 subscriptionId。这样你将拥有 subscriptionIdtheSubscriptionId 列。

¥The first call above will establish a foreign key called theSubscriptionId on Invoice. However, the second call will also establish a foreign key on Invoice (since as we know, hasMany calls places foreign keys in the target model) - however, it will be named subscriptionId. This way you will have both subscriptionId and theSubscriptionId columns.

最好的方法是为外键选择一个名称并将其显式放置在两次调用中。例如,如果选择 subscription_id

¥The best approach is to choose a name for the foreign key and place it explicitly in both calls. For example, if subscription_id was chosen:

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