Javascript “问题”;包括「;使用复合外键时使用Sequelize
以下是我的主表示例:Javascript “问题”;包括「;使用复合外键时使用Sequelize,javascript,mysql,sql,node.js,sequelize.js,Javascript,Mysql,Sql,Node.js,Sequelize.js,以下是我的主表示例: +-------------+------------------------+--------------------+ | tenant | vas_id | friendly_name | +-------------+------------------------+--------------------+ | brand_1 | 1gb_data_zone1 | 1GB Data in
+-------------+------------------------+--------------------+
| tenant | vas_id | friendly_name |
+-------------+------------------------+--------------------+
| brand_1 | 1gb_data_zone1 | 1GB Data in Zone 1 |
| brand_1 | promo_summer_2019_10GB | 10GB for Summer |
| brand_1 | roaming_prepaid | Roaming |
| brand_1 | voicemail_prepaid | Voicemail |
| brand_2 | test_vas | Test |
| brand_2 | roaming_prepaid | Roaming |
| brand_2 | voicemail_prepaid | Voicemail |
+-------------+------------------------+--------------------+
tenant
和vas_id
是此表中的两个主键(也称为复合主键),它们一起用作另一个表的constain,1:N关系:
+---------+------------------------+-----------------+-------------------+-------------------+
| tenant | vas_id | activation_cost | deactivation_cost | modification_cost |
+---------+------------------------+-----------------+-------------------+-------------------+
| brand_1 | 1gb_data_zone1 | 2000 | 0 | 0 |
| brand_1 | promo_summer_2019_10GB | 0 | 0 | 0 |
| brand_1 | roaming_prepaid | 0 | 0 | 0 |
| brand_1 | voicemail_prepaid | 0 | 0 | 0 |
| brand_2 | test_vas | 0 | 0 | 0 |
| brand_2 | roaming_prepaid | 0 | 0 | 0 |
| brand_2 | voicemail_prepaid | 0 | 0 | 0 |
+---------+------------------------+-----------------+-------------------+-------------------
您认为这种结构可以与Sequelize配合使用吗?
以下是我用来标记两个主键的代码:
const vas = serviceLayerDB.define('vas',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
}
friendly_name: {
type: Sequelize.STRING(100)
}
}
const vas_pricing = serviceLayerDB.define('vas_pricing',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
},
activation_cost: {
type: Sequelize.NUMBER
},
deactivation_cost: {
type: Sequelize.NUMBER
},
modification_cost: {
type: Sequelize.NUMBER
}
});
const vas = serviceLayerDB.define('vas',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
// primaryKey: true - NOT ANYMORE
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
}
friendly_name: {
type: Sequelize.STRING(100)
}
}
const vas_pricing = serviceLayerDB.define('vas_pricing',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
// primaryKey: true - NOT ANYMORE
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
},
activation_cost: {
type: Sequelize.NUMBER
},
deactivation_cost: {
type: Sequelize.NUMBER
},
modification_cost: {
type: Sequelize.NUMBER
}
});
…这是我用来将上表与另一个表(vas_定价)关联的代码:
例如,在执行主表和子表中的以下代码时,会发生奇怪的事情:
let options = {
where: {
tenant: 'brand_1',
vas_id: 'promo_summer_2019_10GB'
},
include: [
{
model: vas_pricing,
required: false
}
]
};
vas.findAll(options)
.then(function(data) {
console.log(JSON.stringify(data, null, 2))
})
.catch(function(error) {
console.error(error);
});
结果:
[
{
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"friendly_name": "10GB During Summer",
"vas_pricing": {
"tenant": "brand_1",
"vas_id": "1gb_data_zone1",
"activation_cost": 20,
"deactivation_cost": 0,
"modification_cost": 0
}
},
{
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"friendly_name": "10GB During Summer",
"vas_pricing": {
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"activation_cost": 0,
"deactivation_cost": 0,
"modification_cost": 0
}
},
{
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"friendly_name": "10GB During Summer",
"vas_pricing": {
"tenant": "brand_1",
"vas_id": "roaming_prepaid",
"activation_cost": 0,
"deactivation_cost": 0,
"modification_cost": 0
}
},
{
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"friendly_name": "10GB During Summer",
"vas_pricing": {
"tenant": "brand_1",
"vas_id": "voicemail_prepaid",
"activation_cost": 0,
"deactivation_cost": 0,
"modification_cost": 0
}
}
]
预期结果:
[
{
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"friendly_name": "10GB During Summer",
"vas_pricing": {
"tenant": "brand_1",
"vas_id": "promo_summer_2019_10GB",
"activation_cost": 0,
"deactivation_cost": 0,
"modification_cost": 0
}
}
]
几天来,我一直在绞尽脑汁寻找解决方案,但没有成功。有什么想法吗?在我看来,比起
vas
,你更喜欢vas\u定价。因此,我建议您在vas\u pricing
上进行查询:
let options = {
where: {
tenant: 'brand_1',
vas_id: 'promo_summer_2019_10GB'
},
include: [
{
model: vas,
required: false
}
]
};
vas_pricing.findAll(options)
.then(function(data) {
console.log(JSON.stringify(data, null, 2))
})
.catch(function(error) {
console.error(error);
});
因此,经过大量研究,我得出结论,当同时使用两个外键并试图在子模型中查找时,Sequelize将出现问题
我的解决方法是保持数据库中的结构,并将第二个键设置为唯一键,并告诉Sequelize它是唯一的主键和外键,即使不是
这样Sequelize就可以工作了,我将所有数据保持在数据库级别的一致性
更改概述:
let options = {
where: {
tenant: 'brand_1',
vas_id: 'promo_summer_2019_10GB'
},
include: [
{
model: vas_pricing,
required: false
}
]
};
vas.findAll(options)
.then(function(data) {
console.log(JSON.stringify(data, null, 2))
})
.catch(function(error) {
console.error(error);
});
tenant
和vas\u id
仍然是vas\u pricing
表的主键和复合外键。但是vas_id
现在是唯一的:
+-------------+------------------------+--------------------+
| tenant | vas_id (unique) | friendly_name |
+-------------+------------------------+--------------------+
| brand_1 | 1gb_data_zone1 | 1GB Data in Zone 1 |
| brand_1 | promo_summer_2019_10GB | 10GB for Summer |
| brand_1 | roaming_prepaid_b1 | Roaming |
| brand_1 | voicemail_prepaid_b1 | Voicemail |
| brand_2 | test_vas | Test |
| brand_2 | roaming_prepaid_b2 | Roaming |
| brand_2 | voicemail_prepaid_b2 | Voicemail |
+-------------+------------------------+--------------------+
在vas_pricing
表中,一切都保持原样:
+---------+------------------------+-----------------+-------------------+-------------------+
| tenant | vas_id | activation_cost | deactivation_cost | modification_cost |
+---------+------------------------+-----------------+-------------------+-------------------+
| brand_1 | 1gb_data_zone1 | 2000 | 0 | 0 |
| brand_1 | promo_summer_2019_10GB | 0 | 0 | 0 |
| brand_1 | roaming_prepaid | 0 | 0 | 0 |
| brand_1 | voicemail_prepaid | 0 | 0 | 0 |
| brand_2 | test_vas | 0 | 0 | 0 |
| brand_2 | roaming_prepaid | 0 | 0 | 0 |
| brand_2 | voicemail_prepaid | 0 | 0 | 0 |
+---------+------------------------+-----------------+-------------------+-------------------+
我将租户
作为主键之一删除:
const vas = serviceLayerDB.define('vas',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
}
friendly_name: {
type: Sequelize.STRING(100)
}
}
const vas_pricing = serviceLayerDB.define('vas_pricing',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
primaryKey: true
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
},
activation_cost: {
type: Sequelize.NUMBER
},
deactivation_cost: {
type: Sequelize.NUMBER
},
modification_cost: {
type: Sequelize.NUMBER
}
});
const vas = serviceLayerDB.define('vas',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
// primaryKey: true - NOT ANYMORE
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
}
friendly_name: {
type: Sequelize.STRING(100)
}
}
const vas_pricing = serviceLayerDB.define('vas_pricing',
{ // Database columns:
tenant: {
type: Sequelize.STRING(45),
// primaryKey: true - NOT ANYMORE
},
vas_id: {
type: Sequelize.STRING(100),
primaryKey: true
},
activation_cost: {
type: Sequelize.NUMBER
},
deactivation_cost: {
type: Sequelize.NUMBER
},
modification_cost: {
type: Sequelize.NUMBER
}
});
…Sequelize现在将vas_id
视为唯一的主键:
vas.hasOne(vas_pricing, { foreignKey: 'vas_id' });
结果:
let options = {
where: {
tenant: 'brand_1',
vas_id: 'promo_summer_2019_10GB'
},
include: [
{
model: vas_pricing,
required: false
}
]
};
vas.findAll(options)
.then(function(data) {
console.log(JSON.stringify(data, null, 2))
})
.catch(function(error) {
console.error(error);
});
Sequelize现在在查找正确的子条目方面没有问题,MySQL负责数据一致性,以防止在错误的tenant
和vas_id
密钥对中写入错误的数据。我错误地编辑了您的消息。我试着编辑我自己的。请有人回复。你好。这不是我想要达到的,但是非常感谢你的建议。我已经分享了最终的解决方案。由于Sequelize不支持复合外键,所以似乎没有什么可以做的。