Sequelize中BelongsTo/HasOne关联的强制性疑问咨询
具体来说,给定“Animal”和“Person”模型,其中Animal BelongsTo Person、Person HasOne Animal,这是否意味着每一个Animal实例都必然关联一个Person实例(因Animal属于Person)?反过来,是否意味着并非每一个Person实例都有对应的Animal实例(因Person拥有一个Animal)?
示例代码:
const sequelize = new Sequelize() const Person = sequelize.define('Person', { id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4, }, }) const Animal = sequelize.define('Animal', { id: { type: DataTypes.UUID, primaryKey: true, defaultValue: DataTypes.UUIDV4, }, }) Person.hasOne(Animal) Animal.belongsTo(Person) async function foo () { const animals = await Animal.findAll() for (const animal of animals) { /** * Can I be certain that `person` **always** exists, given that Animal BelongsTo Person? * * In other words, does the BelongsTo Association from Animal to Person imply that Animal * must **always** have a Person associated with the Animal? */ const person = await animal.getPerson() } const people = await Person.findAll() for (const person of people) { /** * And the inverse; given that Person hasOne Animal, does this imply that not all People * will have an Animal associated with them? */ const animal = await person.getAnimal() } }
相关文档摘录(翻译后):
原则上,两种方式都可以在Foo和Bar之间建立一对一关系。但当我们说“Foo和Bar之间存在一对一关系”时,并不明确该关系是强制性还是可选的。换句话说,Foo可以没有Bar存在吗?Bar可以没有Foo存在吗? 这些问题的答案有助于我们确定外键列应该放在哪里。
回答
BelongsTo关联本身不强制关联实例必须存在——这完全取决于你是否给外键设置了非空约束。
在你的代码示例里,Animal.belongsTo(Person)会自动在Animal表中生成personId外键字段,但默认情况下这个字段允许为NULL。这意味着你完全可以创建一个不关联任何Person的Animal实例,此时调用animal.getPerson()会返回null。
反过来,Person.hasOne(Animal)只是定义了反向关联的查询方式,它本身也不强制每个Person都必须有对应的Animal。HasOne和BelongsTo的核心区别其实是外键的存放位置:
- BelongsTo的外键在当前模型(Animal)表中
- HasOne的外键在关联模型(Animal)表中(因为你这里是Person.hasOne(Animal),所以外键还是在Animal表)
如果想要让Animal必须关联Person,你需要在定义BelongsTo的时候显式设置外键为非空:
Animal.belongsTo(Person, { foreignKey: { allowNull: false } })
这样数据库层面会强制personId不能为NULL,此时每个Animal实例就必然关联一个Person了。
总结:
- BelongsTo关联默认是可选的,除非你设置外键
allowNull: false - HasOne关联本身也不强制关联实例存在,是否强制同样取决于外键的约束设置
内容的提问来源于stack exchange,提问作者JamesK

