Difference between HasOne and BelongsTo in Sequelize ORM

后端 未结 3 1312
Happy的楠姐
Happy的楠姐 2020-12-23 12:45

I am developing a sails.js app with sequelize ORM. I am a little confused as to when BelongsTo and HasOne need to be used.

The documentation states that :

3条回答
  •  梦毁少年i
    2020-12-23 13:19

    I know this is a 4-years late answer, but I've been thinking of it, searching the docs, and googling since yesterday. And couldn't find an answer that convinced me about what was happening. Today I've got to a conclusion: the difference is not just a matter of semantics, definitely!

    Let's suppose you have the following statement (from the docs):

    Project.hasMany(Task);
    

    It creates, in Project model, some utility methods on the instances of Project, like: addTask, setTask etc. So you could do something like:

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

    Also, in the database, a foreign key in tasks relation would've been created, pointing to projects relation.

    Now if, instead of Project.hasMany(Task);, I've stated only:

    Task.belongsTo(Project);
    

    Then, similarly, in the database, foreign keys in tasks relation would've been created, pointing to projects relation. But there wouldn't be any addTasks method on project instances though. But, by doing Task.belongsTo(Project);, Sequelize would create a different set of methods, but only on task instances this time. After doing that, you could associate a task to a project using, for example:

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

    The docs defines as source, the model that owns the method used to create the association. So, in:

    • Project.hasMany(Task);: In this statement, Project is the source model. Task is, in turn, the target model.
    • Task.belongsTo(Project);: In this statement, Task is the source model. Project is, in turn, the target model.

    The thing is that, when creating associations using hasOne, hasMany, belongsTo, and belongsToMany, the instances utility methods are created only on the source model. That explains why if you want to have the utility methods created in both Project and Task instances, you must use the two statements for describing the same the association, even though, in the database itself, it will have the same redundant effect (creating a foreign key on tasks relation pointing to projects relation's primary key):

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

    BTW, after writing this answer, I realized that this is the same thing that Vladsyslav Turak is explaining in his answer, but I decided to keep my answer here because it adds some important practical information involving the utility methods stuff.

提交回复
热议问题