一对一关联
一对一关联是通过单个外键连接的两个模型之间的关联.
BelongsTo
BelongsTo 关联是在 source model 上存在一对一关系的外键的关联.
一个简单的例子是 Player 通过 player 的外键作为 Team 的一部分.
class Player extends Model {}
Player.init({/* attributes */}, { sequelize, modelName: 'player' });
class Team extends Model {}
Team.init({/* attributes */}, { sequelize, modelName: 'team' });
Player.belongsTo(Team); // 将向 Player 添加一个 teamId 属性以保存 Team 的主键值
外键
默认情况下,将从目标模型名称和目标主键名称生成 belongsTo 关系的外键.
默认的样式是 camelCase
,但是如果源模型配置为 underscored: true
,那么将使用字段 snake_case
创建 foreignKey.
class User extends Model {}
User.init({/* attributes */}, { sequelize, modelName: 'user' })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize, modelName: 'company' });
// 将 companyId 添加到 user
User.belongsTo(Company);
class User extends Model {}
User.init({/* attributes */}, { underscored: true, sequelize, modelName: 'user' })
class Company extends Model {}
Company.init({
uuid: {
type: Sequelize.UUID,
primaryKey: true
}
}, { sequelize, modelName: 'company' });
// 将 companyUuid 以 company_uuid 名称添加到 user
User.belongsTo(Company);
在已定义 as
的情况下,将使用它代替目标模型名称.
class User extends Model {}
User.init({/* attributes */}, { sequelize, modelName: 'user' })
class UserRole extends Model {}
UserRole.init({/* attributes */}, { sequelize, modelName: 'userRole' });
User.belongsTo(UserRole, {as: 'role'}); // 将 role 添加到 user 而不是 userRole
在所有情况下,默认外键可以用 foreignKey
选项覆盖.
当使用外键选项时,Sequelize 将按原样使用:
class User extends Model {}
User.init({/* attributes */}, { sequelize, modelName: 'user' })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize, modelName: 'company' });
User.belongsTo(Company, {foreignKey: 'fk_company'}); // 将 fk_company 添加到 User
目标键
目标键是源模型上的外键列指向的目标模型上的列. 默认情况下,belongsTo 关系的目标键将是目标模型的主键. 要定义自定义列,请使用 targetKey
选项.
class User extends Model {}
User.init({/* attributes */}, { sequelize, modelName: 'user' })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize, modelName: 'company' });
User.belongsTo(Company, {foreignKey: 'fk_companyname', targetKey: 'name'}); // 添加 fk_companyname 到 User
HasOne
HasOne 关联是在 target model 上存在一对一关系的外键的关联.
class User extends Model {}
User.init({/* ... */}, { sequelize, modelName: 'user' })
class Project extends Model {}
Project.init({/* ... */}, { sequelize, modelName: 'project' })
// 单向关联
Project.hasOne(User)
/*
在此示例中,hasOne 将向 User 模型添加一个 projectId 属性 !
此外,Project.prototype 将根据传递给定义的第一个参数获取 getUser 和 setUser 的方法.
如果启用了 underscore 样式,则添加的属性将是 project_id 而不是 projectId.
外键将放在 users 表上.
你也可以定义外键,例如 如果你已经有一个现有的数据库并且想要处理它:
*/
Project.hasOne(User, { foreignKey: 'initiator_id' })
/*
因为Sequelize将使用模型的名称(define的第一个参数)作为访问器方法,
还可以将特殊选项传递给hasOne:
*/
Project.hasOne(User, { as: 'Initiator' })
// 现在你可以获得 Project.getInitiator 和 Project.setInitiator
// 或者让我们来定义一些自己的参考
class Person extends Model {}
Person.init({ /* ... */}, { sequelize, modelName: 'person' })
Person.hasOne(Person, {as: 'Father'})
// 这会将属性 FatherId 添加到 Person
// also possible:
Person.hasOne(Person, {as: 'Father', foreignKey: 'DadId'})
// 这将把属性 DadId 添加到 Person
// 在这两种情况下,你都可以:
Person.setFather
Person.getFather
// 如果你需要联结表两次,你可以联结同一张表
Team.hasOne(Game, {as: 'HomeTeam', foreignKey : 'homeTeamId'});
Team.hasOne(Game, {as: 'AwayTeam', foreignKey : 'awayTeamId'});
Game.belongsTo(Team);
即使它被称为 HasOne 关联,对于大多数1:1关系,你通常需要BelongsTo关联,因为 BelongsTo 将会在 hasOne 将添加到目标的源上添加 foreignKey.
源键
源关键是源模型中的属性,它是指向目标模型的外键属性. 默认情况下,hasOne
关系的源键将是源模型的主要属性. 要使用自定义属性,请使用sourceKey
参数.
class User extends Model {}
User.init({/* attributes */}, { sequelize, modelName: 'user' })
class Company extends Model {}
Company.init({/* attributes */}, { sequelize, modelName: 'company' });
// 将 companyName 属性添加到 User
// 使用 Company 的 name 属性作为 source 属性
Company.hasOne(User, {foreignKey: 'companyName', sourceKey: 'name'});
HasOne 和 BelongsTo 之间的区别
在Sequelize 1:1关系中可以使用HasOne和BelongsTo进行设置. 它们适用于不同的场景. 让我们用一个例子来研究这个差异.
假设我们有两个表可以链接 Player 和 Team . 让我们定义他们的模型.
class Player extends Model {}
Player.init({/* attributes */}, { sequelize, modelName: 'player' })
class Team extends Model {}
Team.init({/* attributes */}, { sequelize, modelName: 'team' });
当我们连接 Sequelize 中的两个模型时,我们可以将它们称为一对 source 和 target 模型.像这样
将 Player 作为 source 而 Team 作为 target
Player.belongsTo(Team);
//或
Player.hasOne(Team);
将 Team 作为 source 而 Player 作为 target
Team.belongsTo(Player);
//Or
Team.hasOne(Player);
HasOne 和 BelongsTo 将关联键插入到不同的模型中. HasOne 在 target 模型中插入关联键,而 BelongsTo 将关联键插入到 source 模型中.
下是一个示例,说明了 BelongsTo 和 HasOne 的用法.
class Player extends Model {}
Player.init({/* attributes */}, { sequelize, modelName: 'player' })
class Coach extends Model {}
Coach.init({/* attributes */}, { sequelize, modelName: 'coach' })
class Team extends Model {}
Team.init({/* attributes */}, { sequelize, modelName: 'team' });
假设我们的 Player
模型有关于其团队的信息为 teamId
列. 关于每个团队的 Coach
的信息作为 coachId
列存储在 Team
模型中. 这两种情况都需要不同种类的1:1关系,因为外键关系每次出现在不同的模型上.
当关于关联的信息存在于 source 模型中时,我们可以使用 belongsTo
. 在这种情况下,Player
适用于 belongsTo
,因为它具有 teamId
列.
Player.belongsTo(Team) // `teamId` 将被添加到 Player / Source 模型中
当关于关联的信息存在于 target 模型中时,我们可以使用 hasOne
. 在这种情况下, Coach
适用于 hasOne
,因为 Team
模型将其 Coach
的信息存储为 coachId
字段.
Coach.hasOne(Team) // `coachId` 将被添加到 Team / Target 模型中