英文:
Sequelize associations - special methods/mixins are not created?
问题
根据文档:https://sequelize.org/docs/v6/core-concepts/assocs/#special-methodsmixins-added-to-instances
当两个模型之间定义了关联时,这些模型的实例会获得用于与其关联的对应实例进行交互的特殊方法。
特殊方法/混合方法应该对用户实例可用,比如user.addFriend(),user.removeFriend(),当应用了belongsToMany或hasMany关联时,但存在一个问题。
这些方法没有被创建。顺便说一下,数据库中已经创建了'through'表UserFriend。
我不知道这个问题是否与TypeScript有关,还是与创建这种自引用关联的方式有关。我怀疑的第一件事是创建这些关联的方式,但我尝试了所有可能的模型连接方式,特殊方法从未被创建。
有没有办法让我检查这些方法是否已经创建,因为我的IDE显示了这个消息 - 属性'addFriend'在类型'User'上不存在(显然没有被创建)。
如果有人认出这类问题,或者知道我可以在哪里了解更多关于这个主题和这类问题的信息,我将不胜感激。任何建议都将有所帮助。
英文:
As per documentation:https://sequelize.org/docs/v6/core-concepts/assocs/#special-methodsmixins-added-to-instances
When an association is defined between two models, the instances of those models gain special methods to interact with their associated counterparts.
Special methods/mixins should be available to user instance, such like user.addFriend(), user.removeFriend(), when there is an applied belongsToMany,hasMany association, but there is a problem.
import { Model, DataTypes, Optional } from "sequelize";
import sequelize from "../../sequelize";
import { UserAttributes } from "./user.def";
interface UserCreationAttributes extends Optional<UserAttributes, "userId"> { }
export class User
extends Model<UserAttributes, UserCreationAttributes>
implements UserAttributes {
public userId!: number;
public active!: boolean;
public firstName!: string;
public lastName!: string;
public username!: string;
}
const instance = User.init(
{
userId: {
field: "user_id",
type: DataTypes.BIGINT,
primaryKey: true,
autoIncrement: true,
},
active: {
field: "active",
type: DataTypes.BOOLEAN,
defaultValue: true,
allowNull: false,
},
firstName: {
field: "first_name",
type: DataTypes.STRING(100),
allowNull: false,
},
lastName: {
field: "last_name",
type: DataTypes.STRING(100),
allowNull: false,
},
username: {
field: "username",
type: DataTypes.STRING(),
allowNull: false,
unique: true,
},
},
{
sequelize,
tableName: "user",
freezeTableName: true,
}
);
User.belongsToMany(User, { foreignKey: 'friend_id', as: 'Friend', through: 'UserFriend' })
export { instance };
These methods are not created. By the way, the 'through' table UserFriend is created in db.
I don't know if this problem has something with typescript, or with the way of creating this self-referential association. The first thing I suspect is the problem, is the way of creating these associations, but I tried all possibilities for connecting models, and special methods were never created.
Is there any way for me to check if these methods are created, because my IDE shows me this message - Property 'addFriend' does not exist on type 'User' (clearly not created).
If anyone recognizes these types of problem, or where I can learn more about this topic and these types of problems, I'd be very grateful. Any advice will be helpful.
答案1
得分: 1
I have the exact same problem going on right now. 我现在遇到完全相同的问题。
I don't have a complete solution but I do have part of it. 我没有完整的解决方案,但我有一部分。
I'll say that this code contains some kind of bug, but refer you to the incomplete yet still useful docs for combining TypeScript with Sequelize to try to fix the bug. 我会说这段代码包含某种错误,但会引导您查阅 将 TypeScript 与 Sequelize 结合使用 的文档来尝试修复该错误。
I don't know which associations you would make in your code, but for me I have a Profile model that connects to the Account model, Housing model and Gym model, like this: 我不知道您在代码中会建立哪些关联,但对我来说,我有一个 Profile 模型,它连接到 Account 模型、Housing 模型和 Gym 模型,就像这样:
And the relationship between Profile, Account, Housing, and Gym are like this: Profile、Account、Housing 和 Gym 之间的关系如下:
Hence now I can do profile.getHousings();
and profile.addHousing(housing);
因此,现在我可以执行 profile.getHousings();
和 profile.addHousing(housing);
英文:
I have the exact same problem going on right now. I don't have a complete solution but I do have part of it. I'll say that this code contains some kind of bug, but refer you to the incomplete yet still useful docs for combining TypeScript with Sequelize to try to fix the bug.
I don't know which associations you would make in your code, but for me I have a Profile model that connects to the Account model, Housing model and Gym model, like this:
export class Profile extends Model<ProfileAttributes, ProfileCreationAttributes> implements ProfileAttributes {
public profileId!: number;
public acctId!: ForeignKey<Account["acctId"]>;
public ipAddress!: string;
public readonly createdAt!: Date;
public readonly updatedAt!: Date;
public readonly deletedAt!: Date;
declare getAccount: BelongsToGetAssociationMixin<Account>;
declare setAccount: BelongsToSetAssociationMixin<Account, number>;
declare getHousings: HasManyGetAssociationsMixin<Housing>;
declare addHousing: HasManyAddAssociationMixin<Housing, number>;
declare addHousings: HasManyAddAssociationsMixin<Housing, number>;
declare getGyms: HasManyGetAssociationsMixin<Gym>;
declare addGym: HasManyAddAssociationMixin<Gym, number>;
declare addGyms: HasManyAddAssociationsMixin<Gym, number>;
public readonly Housings?: Housing[];
public readonly Gyms?: Gym[];
public static associations: {
Housings: Association<Profile, Housing>;
Gyms: Association<Profile, Gym>;
};
static initModel(sequelize: S): typeof Profile {
return Profile.init(
{
profileId: {
type: DataTypes.INTEGER,
unique: true,
autoIncrement: true,
primaryKey: true,
},
ipAddress: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
timestamps: true,
sequelize: sequelize,
paranoid: false,
},
);
}
}
And the relationship between Profile, Account, Housing, and Gym are like this:
Account.hasOne(Profile, { foreignKey: "acctId", as: "profile" });
Profile.belongsTo(Account, { foreignKey: "acctId", as: "account" });
// https://sequelize.org/docs/v6/advanced-association-concepts/advanced-many-to-many/
Profile.belongsToMany(Housing, { through: "Profile_Housings", as: "housings" });
Housing.belongsToMany(Profile, { through: "Profile_Housings", as: "profile" });
Profile.belongsToMany(Gym, { through: "Profile_Gyms", as: "gyms" });
Gym.belongsToMany(Profile, { through: "Profile_Gyms", as: "profile" });
Profile.hasMany(Feedback, { foreignKey: "profileId", as: "their_feedback" });
Feedback.belongsTo(Profile, { foreignKey: "profileId", as: "feedback_from" });
Hence now I can do profile.getHousings();
and profile.addHousing(housing);
答案2
得分: 1
以下是已翻译的内容:
问题在于这些函数是在运行时定义的,而 TypeScript 会在编译时失败,如果它们在编译时没有声明,这就是为什么你需要在模型中自己声明它们的签名,只有签名,实现由 sequelize 自身负责。由于你有一个 belongsToMany 关系,你可以在模型类中如下添加以下签名:
export class User
extends Model<UserAttributes, UserCreationAttributes>
implements UserAttributes {
public userId!: number;
public active!: boolean;
public firstName!: string;
public lastName!: string;
public username!: string;
declare getFriends: BelongsToManyGetAssociationsMixin<User>;
declare addFriend: BelongsToManyAddAssociationsMixin<User, number>;
// 等等...
}
请参阅 https://sequelize.org/docs/v6/other-topics/typescript/#usage
英文:
The problem is that these functions are defined in runtime while typescript is going to fail if they are not declared in compile time, this is why you need to declare their signatures in the model yourself, only the signature, the implementation is taken care of by sequelize itself. since you have a belongsToMany relation you can add the following signatures as follows in the model class
export class User
extends Model<UserAttributes, UserCreationAttributes>
implements UserAttributes {
public userId!: number;
public active!: boolean;
public firstName!: string;
public lastName!: string;
public username!: string;
declare getFriends: BelongsToManyGetAssociationsMixin<User>;
declare addFriend: BelongsToManyAddAssociationsMixin<User, number>;
// etc...
}
see https://sequelize.org/docs/v6/other-topics/typescript/#usage
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论