Yii2 存在数据库事务验证规则
Yii2 exist validation rule on database transaction
我模型中的一个函数使用事务将行保存在两个不同的 table、table_1 和 table_2 中。在 table_2 中,一个外键引用 table_1.id 并且由 gii 自动生成的验证规则是类型 "exist"。当我需要保存行时,第一步是开始数据库事务,第二步是设置并保存 table_1 行,最后设置并保存与 [=34= 相关的 table_2 行] 行,如果两个插入都正常,则事务将提交,否则回滚。问题是当我将 table_1 行的 id 传递给 table_2 并且验证失败,因为 table_1 的 id 无效,但是 id 是在同一个脚本中生成的,是这个交易有问题?
编辑 1:
产生错误的操作:
$order = new OrdersToImport();
$transaction = OrdersToImport::getDb()->beginTransaction();
... //operations on $order
if($order->save()){
$detail = new OrdersToImportD();
... //operations on $detail
$detail->id_order = $order->id;
if(!$detail->save()){
$transaction->rollback();
return -1;
}
}
数据校验代码:
[['id_order'], 'exist', 'skipOnError' => true, 'targetClass' => OrdersToImport::className(), 'targetAttribute' => ['id_order' => 'id']]
编辑 2:
结果:
if(!$detail->save()){
echo "$order->id";
echo "$detail->id_order";
var_dump($detail->errors);
die();
}
是:
187
187
array(1) { ["id_order"]=> array(1) { [0]=> string(20) "Id Order is invalid." } }
These was generated from gii, I suppose that all the rules thus
generated are right
是的,这些规则是正确的,并且在大多数情况下都很好。
并不意味着它们在任何情况下都有效;
我从评论中假设您的结构是这样的:
(如果我错了,请使用适当的详细信息更新您的问题):
为了简单起见,我将它们称为 Order 和 OrderDetail
生成的模型: 这些包含您提到的 existance
规则
common\models\Order
common\models\OrderDetail
带有自定义 db: 的模型包含不同的 getDb()
定义,并扩展了上面生成的两个模块
common\modules\samplemodule\models\Order
common\modules\samplemodule\models\OrderDetail
现在 samplemodule
中的模型将继承生成模型的规则。
注意 common\models\OrderDetail
中此生成规则的 targetClass
:
[['id_order'], 'exist', 'skipOnError' => true, 'targetClass' => Order::className(), 'targetAttribute' => ['id_order' => 'id']]
Order::className()
表示 common\models\Order::className()
,这意味着所有子 classes(无论命名空间如何)都将具有引用 common\models\Order
.
的存在规则
在您的情况下:modules\samplemodule\models\OrderDetail
(使用不同的数据库)将验证是否存在 common\models\Order
(来自默认数据库的订单)
所以这是我提出的解决方案:
for common\models\OrderDetail
(生成的class)去掉existence
规则,在单独的方法中定义
namespace common\models;
class OrderDetail extends ActiveRecord {
//..
public function rules(){
return ArrayHelper::merge([
// ..
// all the default generated rules except the existance ones
], static::existenceRules());
}
protected static function existenceRules(){
return [
[['id_order'], 'exist', 'skipOnError' => true,
// fqn not required it's just here to highlight the difference
'targetClass' => common\models\Order::className(),
'targetAttribute' => ['id_order' => 'id']]
];
}
// ..
}
为了 common\modules\samplemodule\models\OrderDetail
覆盖我们之前创建的 existanceRules()
方法 link 正确的目标 class
namespace common\modules\samplemodule\models;
class OrderDetail extends common\models\OrderDetail {
//..
// custom db:
public static function getDb(){
return Yii::$app->moduleDatabase;
}
// optional (if you need more rules here):
public function rules(){
return ArrayHelper::merge( parent::rules(), [
// rules that apply only in this context (this db)
]);
}
// this is required if to reference the correct `targetClass`
protected static function existenceRules(){
return [
[['id_order'], 'exist', 'skipOnError' => true,
'targetClass' => common\modules\samplemodule\models\Order::className(),
'targetAttribute' => ['id_order' => 'id']]
];
}
// ..
}
在这两种情况下,我都使用了目标的全名 class 来帮助突出差异,因为它们使用不同的数据库,所以相同的规则不能同时适用于父项和子项 class .
希望对您有所帮助。祝你好运。
我模型中的一个函数使用事务将行保存在两个不同的 table、table_1 和 table_2 中。在 table_2 中,一个外键引用 table_1.id 并且由 gii 自动生成的验证规则是类型 "exist"。当我需要保存行时,第一步是开始数据库事务,第二步是设置并保存 table_1 行,最后设置并保存与 [=34= 相关的 table_2 行] 行,如果两个插入都正常,则事务将提交,否则回滚。问题是当我将 table_1 行的 id 传递给 table_2 并且验证失败,因为 table_1 的 id 无效,但是 id 是在同一个脚本中生成的,是这个交易有问题?
编辑 1:
产生错误的操作:
$order = new OrdersToImport();
$transaction = OrdersToImport::getDb()->beginTransaction();
... //operations on $order
if($order->save()){
$detail = new OrdersToImportD();
... //operations on $detail
$detail->id_order = $order->id;
if(!$detail->save()){
$transaction->rollback();
return -1;
}
}
数据校验代码:
[['id_order'], 'exist', 'skipOnError' => true, 'targetClass' => OrdersToImport::className(), 'targetAttribute' => ['id_order' => 'id']]
编辑 2:
结果:
if(!$detail->save()){
echo "$order->id";
echo "$detail->id_order";
var_dump($detail->errors);
die();
}
是:
187
187
array(1) { ["id_order"]=> array(1) { [0]=> string(20) "Id Order is invalid." } }
These was generated from gii, I suppose that all the rules thus generated are right
是的,这些规则是正确的,并且在大多数情况下都很好。
并不意味着它们在任何情况下都有效;
我从评论中假设您的结构是这样的:
(如果我错了,请使用适当的详细信息更新您的问题):
为了简单起见,我将它们称为 Order 和 OrderDetail
生成的模型: 这些包含您提到的
existance
规则common\models\Order
common\models\OrderDetail
带有自定义 db: 的模型包含不同的
getDb()
定义,并扩展了上面生成的两个模块
common\modules\samplemodule\models\Order
common\modules\samplemodule\models\OrderDetail
现在 samplemodule
中的模型将继承生成模型的规则。
注意 common\models\OrderDetail
中此生成规则的 targetClass
:
[['id_order'], 'exist', 'skipOnError' => true, 'targetClass' => Order::className(), 'targetAttribute' => ['id_order' => 'id']]
Order::className()
表示 common\models\Order::className()
,这意味着所有子 classes(无论命名空间如何)都将具有引用 common\models\Order
.
的存在规则
在您的情况下:modules\samplemodule\models\OrderDetail
(使用不同的数据库)将验证是否存在 common\models\Order
(来自默认数据库的订单)
所以这是我提出的解决方案:
for common\models\OrderDetail
(生成的class)去掉existence
规则,在单独的方法中定义
namespace common\models;
class OrderDetail extends ActiveRecord {
//..
public function rules(){
return ArrayHelper::merge([
// ..
// all the default generated rules except the existance ones
], static::existenceRules());
}
protected static function existenceRules(){
return [
[['id_order'], 'exist', 'skipOnError' => true,
// fqn not required it's just here to highlight the difference
'targetClass' => common\models\Order::className(),
'targetAttribute' => ['id_order' => 'id']]
];
}
// ..
}
为了 common\modules\samplemodule\models\OrderDetail
覆盖我们之前创建的 existanceRules()
方法 link 正确的目标 class
namespace common\modules\samplemodule\models;
class OrderDetail extends common\models\OrderDetail {
//..
// custom db:
public static function getDb(){
return Yii::$app->moduleDatabase;
}
// optional (if you need more rules here):
public function rules(){
return ArrayHelper::merge( parent::rules(), [
// rules that apply only in this context (this db)
]);
}
// this is required if to reference the correct `targetClass`
protected static function existenceRules(){
return [
[['id_order'], 'exist', 'skipOnError' => true,
'targetClass' => common\modules\samplemodule\models\Order::className(),
'targetAttribute' => ['id_order' => 'id']]
];
}
// ..
}
在这两种情况下,我都使用了目标的全名 class 来帮助突出差异,因为它们使用不同的数据库,所以相同的规则不能同时适用于父项和子项 class .
希望对您有所帮助。祝你好运。