Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.8k views
in Technique[技术] by (71.8m points)

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

I have 2 models, one is called User and the second Preferences. There is an association between both:

User.hasOne(Preferences)

Assuming user is an instance of User and pref one of Preferences And a statement like:

user.setPreferences(pref)

Then AFAIU user and pref are somehow linked (even if not stored in database yet). Then, from a user perspective, how can I access to its associated preferences. Using getPreferences() will call the DB which is useless in this case... I have checked for user.preferences and user._preferences but both are undefined.

Is there an easy way to have a handler on associated items ?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The user.Preferences is populated when explicitly requested in code like this:

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

It will send SQL to DB. Otherwise, the value is undefined.

The easiest way is to create the private property on the User model class and store the associated preferences model instances for each user instance after executing user.setPreferences(pref) successfully without calling DB.

E.g. using "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();
})();

Output:

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 ($1) RETURNING *;
Executing (default): SELECT "id" FROM "User" AS "User" WHERE "User"."id" = 1;
Executing (default): INSERT INTO "Preference" ("id","name") VALUES ($1,$2) RETURNING *;
Executing (default): SELECT "id", "name", "UserId" FROM "Preference" AS "Preference" WHERE "Preference"."UserId" = 1;
Executing (default): UPDATE "Preference" SET "UserId"=$1 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
  }
]

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...