【问题标题】:Sequelize - How To Design One To One Association?Sequelize - 如何设计一对一关联?
【发布时间】:2019-10-20 14:27:51
【问题描述】:

我正在创建两个模型,第一个是User,第二个是Portfolio。当用户创建Portfolio(用户只能拥有一个Portfolio)时,我希望它能够引用创建它的用户,并且每次获取该用户的数据时,我希望它也获取他们的投资组合数据(如果有)。

我正在尝试使用hasOneUser 表中创建portfolio_id,并使用sequelize init 命令生成骨架,但它不起作用。如果我不将其放在用户迁移文件中,我将找不到名称为 protfolio_id 的列。应该是这样吗?

我应该如何设计模型?我应该在User 表中包含portfolio_id 并在Portfolio 表中包含user_id,还是有最好的方法?

我应该使用哪种关联方法,hasOne 还是 belongsTo?

【问题讨论】:

    标签: node.js model sequelize.js associations one-to-one


    【解决方案1】:

    首先确保您为每个模型调用Model.associate。这将为所有关系运行查询。

    您可以在 associate 方法中定义如下关系:

    // user.js (User Model definition)
    module.exports = (sequelize, dataTypes) => {
        const { STRING } = dataTypes
        const User = sequelize.define("user", {
            username: { type: STRING }
        })
    
        User.associate = models => {
            User.hasOne(models.Portfolio, { foreignKey: "userId" }) // If only one portfolio per user
            User.hasMany(models.Portfolio) // if many portfolios per user
        }
    
        return User
    }
    
    // portfolio.js (Portfolio Model definition)
    module.exports = (sequelize, dataTypes) => {
        const { STRING } = dataTypes
        const Portfolio = sequelize.define("portfolio", {
            portfolioName: { type: STRING }
        })
    
        Portfolio.associate = models => {
            Portfolio.belongsTo(models.User, { foreignKey: "userId" })
        }
    
        return Portfolio
    }
    

    hasOne 将 foreignKey 存储在目标模型中。所以这个关系会给Portfolio模型添加一个外键userId

    belongsTo 存储当前模型中的键,并引用目标模型的主键。在这种情况下,Portfolio.belongsTo 将在 Portfolio 模型中添加 userId,这将引用 User 模型的主键。

    注意这两种关系是如何做同样的事情的,它们将 userId 添加到 Portfolio 模型中。最好在两个模型中为您的最后一个用例定义这个:

    我希望它能够引用创建它的用户,并且每次获取该用户的数据时,我希望它也获取他们的投资组合数据(如果有的话)。

    访问相关模型:

    在 sequelize 中,将相关模型与主模型一起获取称为 Eager Loading。阅读更多关于它的信息here

    现在对于您的用例,如果您想获取投资组合(如果有的话),请在获取用户时执行以下操作:

    var userWithPortfolio = await User.findAll({include: [models.Portfolio]};
    // Or you may also use include: {all: true} to include all related models.
    var userWithPortfolio = await User.findAll({include: {all: true}};
    
    /*  
        Output:
    
        userWithPortfolio = {
            username: "xyz",
            portfolio: {
                portfolioName: "xyz"
            }
        }
    */
    

    【讨论】:

    • sequelize db:migrate被执行时,它会在Portfolio表上自动创建user_id吗?或者它不应该那样工作,所以我应该在迁移文件中手动定义外键?
    • 如果您可以在数据库表中丢失数据,只需在所有模型上调用 associate 后运行 call sequelize.sync({force: true})。调用sync({force: true})删除所有表并使用新定义从头开始创建它们。如果您不想丢失数据,则必须create a migration for association,如链接帖子中所示
    • 如果Portfolio表已经有user_idUser表中引用id,那么你可能只需要重启服务器
    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    • 1970-01-01
    相关资源
    最近更新 更多