命名策略
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,因此我们应该期望 createdAt
和 updatedAt
字段也会自动创建。
¥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 namedcreatedAt
in each table -
每个模型都有一个
updatedAt
属性,指向每个表中名为updatedAt
的列¥An
updatedAt
attribute for each model, pointing to a column namedupdatedAt
in each table -
Task
模型中的userId
属性,指向任务表中名为userId
的列¥A
userId
attribute in theTask
model, pointing to a column nameduserId
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 namedcreated_at
in each table -
每个模型都有一个
updatedAt
属性,指向每个表中名为updated_at
的列¥An
updatedAt
attribute for each model, pointing to a column namedupdated_at
in each table -
Task
模型中的userId
属性,指向任务表中名为user_id
的列¥A
userId
attribute in theTask
model, pointing to a column nameduser_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:
-
当包含来自单个关联(
hasOne
或belongsTo
)的内容时 - 字段名称将是模型名称的单数版本;¥When including something from a single association (
hasOne
orbelongsTo
) - the field name will be the singular version of the model name; -
当包含来自多重关联(
hasMany
或belongsToMany
)的内容时 - 字段名称将是模型的复数形式。¥When including something from a multiple association (
hasMany
orbelongsToMany
) - 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
。这样你将拥有 subscriptionId
和 theSubscriptionId
列。
¥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' });