Я создаю две модели, первая — User, а вторая — Portfolio. Когда пользователь создает Portfolio (где у пользователя может быть только один Portfolio), я хочу, чтобы он имел ссылку на пользователя, который его создает, и каждый раз, когда данные этого пользователя извлекаются, я хотите, чтобы он также извлекал данные их портфолио, если таковые имеются.

Я пытаюсь использовать hasOne для создания portfolio_id внутри таблиц User со скелетом, сгенерированным с помощью команды sequelize init, но это не работает. Я не могу найти столбец с именем protfolio_id, если не поместил его в файл миграции пользователей. Так должно быть?

Как мне проектировать модели? Должен ли я включать portfolio_id в таблицы User и включать user_id в таблицу Portfolio, или есть лучший способ сделать это?

И какой метод ассоциаций мне следует использовать, hasOne или ownTo?

0
Ari 20 Окт 2019 в 09:00

1 ответ

Прежде всего убедитесь, что вы вызываете Model.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 сохраняет внешний ключ в целевой модели. Таким образом, эта связь добавит внешний ключ userId к модели Portfolio.

belongsTo хранит ключ в текущей модели и ссылается на первичный ключ целевой модели. В этом случае Portfolio.belongsTo добавит userId в модель Portfolio, которая будет ссылаться на первичный ключ модели User.

Обратите внимание, что обе эти связи делают одно и то же: они добавляют идентификатор пользователя в модель портфеля. Лучше определить это в обеих моделях для вашего последнего варианта использования:

Я хочу, чтобы он имел ссылку на пользователя, который его создает, и каждый раз, когда данные этого пользователя извлекаются, я хочу, чтобы он также извлекал данные их портфолио, если таковые имеются.

Доступ к связанным моделям:

В дальнейшем извлечение связанной модели вместе с основной моделью называется Нетерпеливая загрузка. Подробнее об этом читайте здесь.

Теперь для вашего варианта использования, если вы хотите получить портфолио, если оно есть, при извлечении пользователя сделайте следующее:

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"
        }
    }
*/
2
Hussain Nawaz Lalee 20 Окт 2019 в 09:27
Создает ли он автоматически user_id в таблице Portfolio при выполнении sequelize db:migrate? Или это не должно так работать, поэтому я должен вручную указать внешний ключ в файле миграции?
 – 
Ari
20 Окт 2019 в 15:46
1
Если вы согласны с потерей данных в таблицах базы данных, просто запустите вызов sequelize.sync({force: true}) после вызова ассоциирования на всех моделях. Вызов sync({force: true}) удалит все таблицы и создаст их с нуля, используя новые определения. Если вы не хотите потерять данные, вам придется создайте миграцию для ассоциации, как показано в связанном посте
 – 
Hussain Nawaz Lalee
20 Окт 2019 в 16:17
Если в таблице Portfolio уже есть user_id, который ссылается на id в таблице User, вам может потребоваться только перезапустить сервер.
 – 
Hussain Nawaz Lalee
20 Окт 2019 в 16:28