Sequelize.js - 如何访问关联的内存项目

Sequelize.js - How to access associated in-memory items

我有 2 个模型,一个称为 User,第二个称为 Preferences。 两者之间存在关联:

User.hasOne(Preferences)

假设 user 是 User 的一个实例并且 pref 是 Preferences 之一 还有这样的声明:

user.setPreferences(pref)

然后 AFAIU 用户和 pref 以某种方式链接(即使尚未存储在数据库中)。 然后,从用户的角度来看,我如何才能访问其关联的首选项。 使用 getPreferences() 将调用在这种情况下无用的数据库...... 我检查了 user.preferences 和 user._preferences 但两者都未定义。

是否有一种简单的方法来处理相关项目?

user.Preferences 在代码中明确请求时填充,如下所示:

const user2: User = await User.findOne({ where: { id: 1 }, include: [Preference] });
console.log(user2.Preferences); // it's only populated when explicitly requested in code

它将SQL发送到数据库。否则,值为 undefined.

最简单的方法是在 User 模型 class 上创建私有 属性 并在执行后为每个用户实例存储关联的 preferences 模型实例 user.setPreferences(pref) 没有调用 DB 就成功了。

例如使用 "sequelize": "^5.21.3"

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

class User extends Model {
  public id!: number;

  public getPreferences!: HasManyGetAssociationsMixin<Preference>;
  public setPreferences!: HasManySetAssociationsMixin<Preference, Preference['id']>;
  public readonly Preferences?: Preference[];

  public _inMemoryAssociatedPreferences: Preference[] = [];
}
User.init({}, { sequelize });

class Preference extends Model {
  public id!: number;
  public name!: string;
}
Preference.init({ name: DataTypes.STRING }, { sequelize });

User.hasMany(Preference);
Preference.belongsTo(User);

(async function test() {
  await sequelize.sync({ force: true });
  await User.create({ id: 1 });
  const user: User = await User.findOne({ where: { id: 1 } });
  const pref = await Preference.create({ id: 1, name: 'a' });
  await user.setPreferences(pref);
  user._inMemoryAssociatedPreferences = [pref];

  // elsewhere
  console.log('in memory preferences:', user._inMemoryAssociatedPreferences);
  await sequelize.close();
})();

输出:

Executing (default): DROP TABLE IF EXISTS "Preference" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): DROP TABLE IF EXISTS "User" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "User" ("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 = 'User' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Preference" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Preference" ("id"   SERIAL , "name" VARCHAR(255), "UserId" INTEGER REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE, 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 = 'Preference' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): INSERT INTO "User" ("id") VALUES () RETURNING *;
Executing (default): SELECT "id" FROM "User" AS "User" WHERE "User"."id" = 1;
Executing (default): INSERT INTO "Preference" ("id","name") VALUES (,) RETURNING *;
Executing (default): SELECT "id", "name", "UserId" FROM "Preference" AS "Preference" WHERE "Preference"."UserId" = 1;
Executing (default): UPDATE "Preference" SET "UserId"= WHERE "id" IN (1)
in memory preferences: [
  Preference {
    dataValues: { id: 1, name: 'a', UserId: null },
    _previousDataValues: { id: 1, name: 'a', UserId: null },
    _changed: { id: false, name: false, UserId: false },
    _modelOptions: {
      timestamps: false,
      validate: {},
      freezeTableName: true,
      underscored: false,
      paranoid: false,
      rejectOnEmpty: false,
      whereCollection: [Object],
      schema: null,
      schemaDelimiter: '',
      defaultScope: {},
      scopes: {},
      indexes: [],
      name: [Object],
      omitNull: false,
      sequelize: [Sequelize],
      hooks: {}
    },
    _options: {
      isNewRecord: true,
      _schema: null,
      _schemaDelimiter: '',
      attributes: undefined,
      include: undefined,
      raw: undefined,
      silent: undefined
    },
    isNewRecord: false
  }
]