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
中创建 tenant
和 user
- 它工作正常。
怎么了?
我使用 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();
}
}
我想创建两行。
首先,我想创建一个 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
中创建 tenant
和 user
- 它工作正常。
怎么了?
我使用 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();
}
}