Внешний ключ с Sequelize не работает должным образом - PullRequest
0 голосов
/ 05 ноября 2018

Я пытался создать связь между двумя таблицами и хотел добавить внешний ключ.

Две модели: Пользователь и Компания

User.associate = (models) => { User.belongsTo(models.Companies, { foreignKey: 'Company' }); };

Я ожидал, что приведенный выше код заключается в том, что в таблицу пользователей добавляется поле «Идентификатор компании», которое ссылается на идентификатор компании в таблице «Компании».

При запуске кода выше я не вижу создания дополнительных столбцов. Я попытался проверить, создана ли ассоциация внешнего ключа в БД, но она также отсутствует.

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

Может ли кто-нибудь помочь мне понять, что я делаю неправильно? Спасибо за помощь!

Модели / company.js

module.exports = (sequelize, DataTypes) => {
    var Company = sequelize.define('company', {
        company: { type: DataTypes.STRING, primaryKey: true },
    });

    Company.associate = (models) => {
        Company.hasMany(models.user, { as: 'users' });
    };

    Company.sync();

    return Company;
};

Модели / user.js

const uuid = require('uuid/v4');

'use strict';
module.exports = (sequelize, DataTypes) => {
    var User = sequelize.define('user', {
        id: { type: DataTypes.UUID, primaryKey: true },
        name: { type: DataTypes.STRING, allowNull: false }
    });

    User.associate = (models) => {
        User.belongsTo(models.company);
    };

    User.beforeCreate((user, _ ) => {
        user.id = uuid();
        return user;
    });

    User.sync();

    return User;
};

Модели / index.js

'use strict';

var fs        = require('fs');
var path      = require('path');
var Sequelize = require('sequelize');
var basename  = path.basename(__filename);
var env       = process.env.NODE_ENV || 'development';
// var config    = require(__dirname + '/../config/config.js')[env];
var db        = {};

// if (config.use_env_variable) {
//   var sequelize = new Sequelize(process.env[config.use_env_variable], config);
// } else {
//   var sequelize = new Sequelize(config.database, config.username, config.password, config);
// }

const sequelize = new Sequelize('postgres://postgres:user@localhost:5432/mydb');

fs
  .readdirSync(__dirname)
  .filter(file => {
    return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
  })
  .forEach(file => {
      var model = sequelize['import'](path.join(__dirname, file));
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

db.sequelize = sequelize;
db.Sequelize = Sequelize;

module.exports = db;

Ответы [ 4 ]

0 голосов
/ 14 ноября 2018

Ваша модель в порядке! Вы должны удалить sync из файла моделей, а затем проверить файл миграции для моделей с внешним ключом, которые foregin key есть,

для пользователя миграции:

module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable('Users', {
            id: {
                allowNull: false,
                autoIncrement: true,
                primaryKey: true,
                type: Sequelize.UUID
            },
            name: {
                type: Sequelize.STRING
            },
            companyId: {
                type: Sequelize.UUID,
                references: {
                    model: 'Company',// company migration define
                    key: 'id'
                }
            },
            createdAt: {
                allowNull: false,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: false,
                type: Sequelize.DATE
            }
        });
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('Users');
    }
};

для создания таблицы автоматизации из index.js и моделей, которые вы должны установить sequelize-cli

по типу npm install --save sequelize-cli

тогда вы должны выполнить эту команду для создания таблицы моделей в db

sequelize db:migrate
0 голосов
/ 05 ноября 2018

Я предполагаю, что метод associate не вызывается, и, следовательно, ваша ассоциация не создается. Помните, что associate - это не встроенный метод Sequelize, а просто шаблон, используемый сообществом. (Подробнее о этой теме )

Существуют различные подходы к обработке вызовов associate, вот один пример. У вас есть файл models.js, который обрабатывает вашу ассоциацию, и вы инициализируете его внутри своего основного app.js файла.

// app.js (aka your main application)
const models = require('./models')(sequelize, DataTypes);

// models.js
module.exports = (sequelize, DataTypes) => {
    const models = {
        user: require('./userModel')(sequelize, DataTypes),
        company: require('./companyModel')(sequelize, DataTypes)
    };

    Object.keys(models).forEach(key => {
        if (models[key] && models[key].associate) {
            models[key].associate(models);
        }
    });
};

// companyModel.js
module.exports = (sequelize, DataTypes) => {
    var Company = sequelize.define('company', {...});

    Company.associate = (models) => {
        Company.hasMany(models.user, { as: 'users' });
    };

    Company.sync();

    return Company;
};

// userModel.js
module.exports = (sequelize, DataTypes) => {
    var User = sequelize.define('user', {...});

    User.sync();

    return User;
};

Кроме того, к вашему сведению, вы, вероятно, знаете это, но sync следует использовать только для экспериментов или тестирования, а не для производственного приложения.

0 голосов
/ 09 ноября 2018

Мне удалось решить эту проблему.

Проблема была связана с последовательностью, в которой была вызвана синхронизация. В моем исходном коде я вызывал синхронизацию внутри каждой модели. Хотя я добавил опции force и alter, я думаю, что внешние ключи не добавлялись. Итак, я удалил код sync из моделей и добавил его в отдельный цикл внутри index.js.

Это дало мне новую проблему. Таблицы создавались в порядке, который не соответствует порядку, в котором таблицы должны создаваться для работы внешних ключей, поскольку таблицы должны существовать заранее. Я решил ее вручную, указав последовательность sync, и теперь вижу, как создаются столбцы.

Подведем итог: модель defn -> ассоциация модели -> синхронизация модели в последовательности

Спасибо за ваши предложения, члены SO.

0 голосов
/ 05 ноября 2018

Используя foreignKey: 'Company', вы указываете его связать со столбцом с именем Company. Обычно вы также хотите использовать имена таблиц в единственном числе, поэтому company с ассоциацией companies. По умолчанию Sequelize будет использовать первичный ключ для ассоциации, поэтому вам нужно только указать foreignKey, если вы хотите изменить его или установить другие параметры.

const User = sequelize.define(
  'user',
  { /* columns */ },
  { /* options */ }
);
User.associate = (models) => {
    User.belongsTo(models.Company);
};

const Company = sequelize.define(
  'company',
  { /* columns */ },
  { /* options */ }
);
Company.associate = (models) => {
    Company.hasMany(models.User, { as: 'users' });
};

Это создаст следующие таблицы Company (id) и User (id, company_id).

Запрос всех User записей, связанных с одной Company:

const user = await User.findAll({ include: { model: Company } });
/*
user = {
  id: 1,
  company_id: 1,
  company: {
    id: 1,
  },
};
*/

Запрос всех Company записей с несколькими связанными User записями через users:

const company = await User.findAll({ include: { model: User, as: 'users' } });
/*
company = {
  id: 1,
  users: [{
    id: 1
    company_id: 1,
  }],
};
*/
...