首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >HasOne与BelongsTo在后置ORM中的差异

问HasOne与BelongsTo在后置ORM中的差异
EN

Stack Overflow用户
提问于 2016-01-02 11:27:25
回答 4查看 21.7K关注 0票数 59

我正在开发一个sails.js应用程序与后遗症 ORM。对于何时需要使用BelongsTo和HasOne,我有点困惑。

文件指出:

BelongsTo关联是源模型中存在一对一关系的外键的关联。 HasOne关联是目标模型中存在一对一关系的外键的关联。

除了指定的地点外,还有其他的区别吗?在这两种情况下,行为是否仍然是相同的?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-01-02 20:38:17

这是一个更普遍的问题。

主要的区别在于语义上。你必须决定什么是关系(一些愚蠢的例子):

人只有一只右臂。右臂属于一个人。

相反地说它看起来有点奇怪:

右臂有个男人。一个人属于右臂。

你可以拥有没有右臂的男人。但单靠右臂是没用的。

如果RightArm和Man是模型的话,它可能看起来像:

代码语言:javascript
复制
Man.hasOne(RightArm);      // ManId in RigthArm
RightArm.belongsTo(Man);   // ManId in RigthArm

正如您注意到的,db表结构也有差异:

BelongsTo将在hasOne将添加到目标的源上添加foreignKey (Sequelize将在表“RightArm”中创建新列“ManId”,但不会在“Man”表中创建“RightArmId”列)。

我看不出还有什么不同之处。

票数 109
EN

Stack Overflow用户

发布于 2018-05-06 10:56:06

我同意克孜兹托夫关于以下几个方面的区别:

代码语言:javascript
复制
Man.hasOne(RightArm);
RightArm.belongsTo(Man);

我想回答王阳军的问题:

因此,在这种情况下,我应该使用Man.hasOne(RightArm);还是RightArm.belongsTo(Man);?还是两者兼用?

确实,Man.hasOne(RightArm);关系和RightArm.belongsTo(Man);关系做了相同的事情--每个关系都会将外键manId添加到RightArm表中。

从物理数据库层的角度来看,这些方法做了同样的事情,对于我们的数据库来说,我们将使用哪一种精确的方法并没有什么区别。

那么,有什么区别呢?主要的区别在于ORM的层(在我们的例子中它是均衡化 ORM,但下面的逻辑适用于Laravel的雄辩 ORM,甚至适用于活动记录 ORM)。

使用Man.hasOne(RightArm);关系,我们将能够使用Man模型填充男人的RightArm。如果这对我们的应用程序来说已经足够了,我们可以停止使用它,不要将RightArm.belongsTo(Man);关系添加到RightArm模型中。

但是,如果我们需要得到RightArm的所有者呢?如果不在RightArm模型上定义RightArm.belongsTo(Man);关系,我们就无法使用RightArm模型来完成这个任务。

另外一个例子是User和Phone模型。定义User.hasOne(Phone)关系,我们就可以填充User的Phone,不定义Phone.belongsTo(User)关系,就无法填充Phone的所有者(例如User),如果定义Phone.belongsTo(User)关系,就可以得到Phone的所有者。

因此,这里我们有一个主要的区别:如果我们想要填充来自这两个模型的数据,我们需要定义它们的关系(hasOne和belongsTo)。如果我们只需要得到User的Phone,而不能得到Phone的User,我们就只能在User模型上定义User.hasOne(Phone)关系。

上面的逻辑适用于所有具有hasOne和belongsTo关系的ORM。

我希望这能澄清你的理解。

票数 83
EN

Stack Overflow用户

发布于 2020-05-05 19:43:42

我知道这是一个4年后的回答,但我一直在考虑,搜索文档,并搜索从昨天开始。却找不到一个能让我相信发生了什么的答案。今天我得出了一个结论:区别是,而不是,绝对是一个语义问题!

假设您有以下语句(从医生那里):

代码语言:javascript
复制
Project.hasMany(Task);

在Project模型中,它在Project实例上创建了一些实用方法,如:addTask、setTask等。因此,您可以这样做:

代码语言:javascript
复制
const project = await Project.create({...});

// Here, addTask exists in project instance as a 
// consequence of Project.hasMany(Task); statement 
project.addTasks([task1, task2]);

此外,在数据库中,将在tasks关系中创建一个外键,指向projects关系。

现在,如果不是Project.hasMany(Task);,我只说了:

代码语言:javascript
复制
Task.belongsTo(Project);

然后,类似地,在数据库中,将创建tasks关系中的外键,指向projects关系。但是,在addTasks实例上不会有任何project方法。但是,通过执行task,Sequelize将创建一组不同的方法,但这次只能在Task.belongsTo(Project);实例上使用。这样做之后,您可以使用以下方法将任务与项目关联起来:

代码语言:javascript
复制
const proj = await Project.findByPk(...);
const task1 = await Task.create({...});

...

// Here, setProject exists in task instance as a 
// consequence of Task.belongsTo(Project); statement 
task1.setProject(proj);

文档定义为源,该模型拥有用于创建关联的方法。因此,在:

  • Project.hasMany(Task);:在这个语句中,Project是源模型。Task反过来又是目标模型。
  • Task.belongsTo(Project);:在这个语句中,Task是源模型。Project反过来又是目标模型。

问题是,当使用hasOne、hasMany、belongsTo和belongsToMany创建关联时,实例实用程序方法仅在源模型上创建。总之:如果您希望在Project和Task实例中同时创建实用程序方法,则必须使用这两个语句来描述相同的关联。在数据库本身中,两者具有相同的冗余效果(在tasks关系上创建指向projects关系的主键的外键):

代码语言:javascript
复制
// All the instances of Project model will have utility methods
Project.hasMany(Task);

// All the instances of Task model will have utility methods
Task.belongsTo(Project);

const project = await Project.create(...);
const task1 = await Task.create(...);
const task2 = await Task.create(...);

...

// as a consequence of Project.hasMany(Task), this can be done:
project.addTask(task1);

...

// as a consequence of Task.belongsTo(Project), this can be done:
task2.setProject(project);

顺便说一句,写完这个答案后,我意识到这和弗拉季斯拉夫图拉克在他的回答中解释的一样,但是我决定在这里保留我的答案,因为它增加了一些重要的实用信息,包括实用方法之类的东西。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34565360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档