Sequelize:在同一事务中创建两个引用行

Sequelize: Create two referenced Rows in same Transaction

我想创建两行。

首先,我想创建一个 tenant,然后我想创建一个 user,它引用了 tenant

我想在一次交易(注册)中完成此操作。

tenant 会被创建,但是当 sequelize 尝试创建用户时我得到一个错误:

Failing row contains

例程:ExecConstraints

我的数据库映射:

const TenantMapping = sequelize.define('tenant', {
    id: { type: DataTypes.NUMBER, primaryKey: true, autoIncrement: true },
    label: { type: DataTypes.STRING, allowNull: false },
    name: { type: DataTypes.STRING },
    postOfficeBox: { type: DataTypes.STRING },
    street: { type: DataTypes.STRING },
    houseNo: { type: DataTypes.STRING },
    zipCode: { type: DataTypes.STRING, validate: { max: 10 } },
    city: { type: DataTypes.STRING },
    phone: { type: DataTypes.STRING },
    mobilePhone: { type: DataTypes.STRING },
    email: { type: DataTypes.STRING, allowNull: false },
    website: { type: DataTypes.STRING },
    birth: { type: DataTypes.DATE, allowNull: false },
    death: { type: DataTypes.DATE }
}, {
    ...getSequelizeTableSettings({ schema: 'auth' })
});

const UserMapping = sequelize.define('user', {
    id: { type: DataTypes.NUMBER, primaryKey: true, autoIncrement: true },
    tenantId: { type: DataTypes.NUMBER, allowNull: false },
    email: { type: DataTypes.STRING, allowNull: false },
    password: { type: DataTypes.STRING, allowNull: false },
    role: { type: DataTypes.STRING, allowNull: false },
    isActivated: { type: DataTypes.BOOLEAN, allowNull: false },
    birth: { type: DataTypes.DATE, allowNull: false },
    death: { type: DataTypes.DATE }
}, {
    ...getSequelizeTableSettings({ schema: 'auth' })
});

我的控制器


const response = await sequelize.transaction(async (transaction) => {
            try {
                const { tenantLabel, email, password } = req.body;
                const tenant = await this.tenantRepository.create({
                    tenantLabel,
                    email
                }, {
                    transaction
                });

                const user = await this.userRepository.create({
                    email,
                    password,
                    tenantId: tenant.id,
                    role: UserRole.ADMIN
                }, {
                    transaction
                });

                await transaction.commit();
                res.status(200).json({
                    tenant,
                    user
                });
            } catch (exception) {
                res.status(400).send({
                    ...exception
                });
            }
        });

如果我在两个不同的 transactions 中创建 tenantuser - 它工作正常。

怎么了?

我使用 PostgreSQL

{
    "name": "SequelizeDatabaseError",
    "parent": {
        "length": 257,
        "name": "error",
        "severity": "ERROR",
        "code": "23502",
        "detail": "Failing row contains (22, null, email@mail.com, null, null, f, 2022-01-22 12:07:33.899, null).",
        "schema": "auth",
        "table": "user",
        "column": "tenant_id",
        "file": "execMain.c",
        "line": "1965",
        "routine": "ExecConstraints",
        "sql": "INSERT INTO \"auth\".\"user\" (\"id\",\"email\",\"birth\") VALUES (DEFAULT,,) RETURNING \"id\",\"tenant_id\",\"email\",\"password\",\"role\",\"is_activated\",\"birth\",\"death\";",
        "parameters": [
            "email@mail.com",
            "2022-01-22 12:07:33.899 +00:00"
        ]
    },
    "original": {
        "length": 257,
        "name": "error",
        "severity": "ERROR",
        "code": "23502",
        "detail": "Failing row contains (22, null, email@mail.com, null, null, f, 2022-01-22 12:07:33.899, null).",
        "schema": "auth",
        "table": "user",
        "column": "tenant_id",
        "file": "execMain.c",
        "line": "1965",
        "routine": "ExecConstraints",
        "sql": "INSERT INTO \"auth\".\"user\" (\"id\",\"email\",\"birth\") VALUES (DEFAULT,,) RETURNING \"id\",\"tenant_id\",\"email\",\"password\",\"role\",\"is_activated\",\"birth\",\"death\";",
        "parameters": [
            "email@mail.com",
            "2022-01-22 12:07:33.899 +00:00"
        ]
    },
    "sql": "INSERT INTO \"auth\".\"user\" (\"id\",\"email\",\"birth\") VALUES (DEFAULT,,) RETURNING \"id\",\"tenant_id\",\"email\",\"password\",\"role\",\"is_activated\",\"birth\",\"death\";",
    "parameters": [
        "email@mail.com",
        "2022-01-22 12:07:33.899 +00:00"
    ]
}

我记录了我的 object 我想在尝试使用 sequelize 创建之前创建一个新行。

console.log('create new something', JSON.stringify(object));
const response = await this.sequelize.create(object, transaction);

在控制台中我有这个:

create new something {"email":"email@mail.com","password":"bvDzrLah9FjhxG.nlIJjluByE28O6bjyIr4s7LXqoFgGwyjHODJMG","role":"ADMIN","tenantId":22,"isActivated":false}

没错。但是查看错误消息。 Sequelize 尝试仅使用电子邮件创建新用户 - 没有密码,没有角色,没有 tenantId,没有 isActivated...

租户存储库:

export class TenantRepository extends Repository<TenantResource> {

    constructor() {
        super(DB_MAPPINGS.TenantMapping, { identifier: 'id' });
    }

    public async create(
        { tenantLabel, email }: { tenantLabel: string; email: string; },
        { transaction }: { transaction: Transaction }
    ): Promise<TenantResource> {
        return await this.CREATE({
                label: tenantLabel,
                email
            },
            {
                transaction
            }
        );
    }
}

用户资源库:

export class UserRepository extends Repository<UserResource> {

    constructor() {
        super(DB_MAPPINGS.UserMapping, { identifier: 'id' });
    }

    public async create(
        { email, password, role, tenantId }: { email: string; password: string; role: UserRole; tenantId: number; },
        { transaction }: { transaction: Transaction }
    ): Promise<UserResource> {
        return await this.CREATE({
                email,
                password: await this.encryptPassword({ password }),
                role,
                tenantId,
                isActivated: false
            },
            {
                transaction
            }
        );
    }
}

存储库:

export class Repository<T> extends RepositoryHelper<T> {

    public async CREATE(
        object: Partial<T>,
        { transaction }: { transaction: Transaction }
    ): Promise<T> {
        const response = await this.sequelize.create(object, transaction);
        return response.toJSON();
    }

}

我发现了我的问题。我必须通过 transaction.

export class Repository<T> extends RepositoryHelper<T> {

    public async CREATE(
        object: Partial<T>,
        { transaction }: { transaction: Transaction }
    ): Promise<T> {
        const response = await this.sequelize.create(object, { transaction });
        return response.toJSON();
    }

}