繁体   English   中英

Sequelize Many-to-Many Association -- "Include" 查询错误说没有关联

[英]Sequelize Many-to-Many Association -- "Include" query error saying there is no association

我有两个模型,“用户”和“网站”。 每个用户可以有多个网站,每个网站可以有多个用户。

Users.associate = function(models) {
    Users.belongsToMany(models.Websites, {
      through: "UserWebsites",
      as: 'Websites',
      timestamps: false,
    });
  };
Websites.associate = function(models) {
        Websites.belongsToMany(models.Users, {
            through: "UserWebsites",
            as: 'Users',
            timestamps: false,
        });
    };

查询是:

let userId = req.params.id;

  db.Users.findOne({
    where: {
      id: userId
    },
    include: [{ model: db.Websites }]
  }).then(result => console.log(result));

我继续收到一个错误:

Unhandled rejection SequelizeEagerLoadingError: Websites is not associated to Users!

这很奇怪,因为 sequelize 还在 MySQL 中创建了一个“UserWebsites”表,显示关联在那里

它应该工作。 这是一个使用"sequelize": "^5.21.3"的完整工作演示:

index.ts

import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
import assert from 'assert';

class Users extends Model {}
Users.init(
  {
    id: {
      primaryKey: true,
      autoIncrement: true,
      allowNull: false,
      type: DataTypes.INTEGER,
    },
  },
  { sequelize, modelName: 'Users' },
);

class Websites extends Model {}
Websites.init(
  {
    url: DataTypes.STRING,
  },
  { sequelize, modelName: 'Websites' },
);

Users.belongsToMany(Websites, { through: 'UserWebsites', as: 'Websites', timestamps: false });
Websites.belongsToMany(Users, { through: 'UserWebsites', as: 'Users', timestamps: false });

(async function test() {
  try {
    await sequelize.sync({ force: true });
    const websitesOfUser1 = [{ url: 'twitter' }, { url: 'stackoverflow' }];
    const websitesOfUser2 = [{ url: 'github' }, { url: 'google' }];
    // seed
    await Users.bulkCreate(
      [
        { id: 1, Websites: websitesOfUser1 },
        { id: 2, Websites: websitesOfUser2 },
      ],
      { include: [{ model: Websites, as: 'Websites' }] },
    );

    // test
    const user = await Users.findOne({
      where: { id: 1 },
      include: [{ model: Websites, as: 'Websites' }],
    });
    assert.equal(user.Websites.length, websitesOfUser1.length, 'user 1 has two websites');
    const websitesDataValues = user.Websites.map((website) => website.dataValues);
    console.log('websitesDataValues: ', websitesDataValues);
  } catch (error) {
    console.log(error);
  } finally {
    await sequelize.close();
  }
})();

执行结果:

Executing (default): DROP TABLE IF EXISTS "UserWebsites" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Websites" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Users" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Users" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Users" ("id"   SERIAL , PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Websites" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Websites" ("id"   SERIAL , "url" VARCHAR(255), PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Websites' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "UserWebsites" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "UserWebsites" ("UserId" INTEGER  REFERENCES "Users" ("id") ON DELETE CASCADE ON UPDATE CASCADE, "WebsiteId" INTEGER  REFERENCES "Websites" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("UserId","WebsiteId"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'UserWebsites' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "Users" ("id") VALUES (1),(2) RETURNING *;
Executing (default): INSERT INTO "Websites" ("id","url") VALUES (DEFAULT,'twitter'),(DEFAULT,'stackoverflow'),(DEFAULT,'github'),(DEFAULT,'google') RETURNING *;
Executing (default): INSERT INTO "UserWebsites" ("UserId","WebsiteId") VALUES (1,1),(1,2),(2,3),(2,4) RETURNING *;
Executing (default): SELECT "Users"."id", "Websites"."id" AS "Websites.id", "Websites"."url" AS "Websites.url", "Websites->UserWebsites"."UserId" AS "Websites.UserWebsites.UserId", "Websites->UserWebsites"."WebsiteId" AS "Websites.UserWebsites.WebsiteId" FROM "Users" AS "Users" LEFT OUTER JOIN ( "UserWebsites" AS "Websites->UserWebsites" INNER JOIN "Websites" AS "Websites" ON "Websites"."id" = "Websites->UserWebsites"."WebsiteId") ON "Users"."id" = "Websites->UserWebsites"."UserId" WHERE "Users"."id" = 1;
websitesDataValues:  [ { id: 1,
    url: 'twitter',
    UserWebsites:
     UserWebsites {
       dataValues: [Object],
       _previousDataValues: [Object],
       _changed: {},
       _modelOptions: [Object],
       _options: [Object],
       isNewRecord: false } },
  { id: 2,
    url: 'stackoverflow',
    UserWebsites:
     UserWebsites {
       dataValues: [Object],
       _previousDataValues: [Object],
       _changed: {},
       _modelOptions: [Object],
       _options: [Object],
       isNewRecord: false } } ]

查看数据库中的数据记录:

node-sequelize-examples=# select * from "UserWebsites";
 UserId | WebsiteId
--------+-----------
      1 |         1
      1 |         2
      2 |         3
      2 |         4
(4 rows)

node-sequelize-examples=# select * from "Websites";
 id |      url
----+---------------
  1 | twitter
  2 | stackoverflow
  3 | github
  4 | google
(4 rows)

node-sequelize-examples=# select * from "Users";
 id
----
  1
  2
(2 rows)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM