Transactions Yii2数据库事务上存在验证规则
我的模型中的一个函数使用事务将行保存在两个不同的表中,即表1和表2。在表_2中,一个外键指的是表_1.id,由gii自动生成的验证规则为“存在”类型。当我需要保存行时,第一步是开始一个数据库事务,第二步是设置并保存一个表_1行,最后设置并保存与表_1行相关的表_2行,如果两个insert都正常,则事务是commit else rollback。问题是,当我将表_1行的id传递给表_2时,验证失败,因为表_1的id无效,但id是在同一脚本中生成的,这是事务的问题吗 编辑1: 生成错误的操作:Transactions Yii2数据库事务上存在验证规则,transactions,yii2,yii2-advanced-app,yii2-model,yii2-validation,Transactions,Yii2,Yii2 Advanced App,Yii2 Model,Yii2 Validation,我的模型中的一个函数使用事务将行保存在两个不同的表中,即表1和表2。在表_2中,一个外键指的是表_1.id,由gii自动生成的验证规则为“存在”类型。当我需要保存行时,第一步是开始一个数据库事务,第二步是设置并保存一个表_1行,最后设置并保存与表_1行相关的表_2行,如果两个insert都正常,则事务是commit else rollback。问题是,当我将表_1行的id传递给表_2时,验证失败,因为表_1的id无效,但id是在同一脚本中生成的,这是事务的问题吗 编辑1: 生成错误的操作: $o
$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();
}
是:
这些都是从gii生成的,我想所有的规则都是这样的
你是对的
是的,规则是正确的,并且在大多数用例中都很好。这并不意味着他们在任何情况下都能工作 我从评论中推测您的结构如下:
(如果我错了,请用适当的细节更新您的问题):
为了简单起见,我将它们称为Order和OrderDetail
- 生成的模型:这些模型包含您提到的
存在规则
common\models\Order
common\models\OrderDetail
- 带有自定义数据库的模型:这些模型包含不同的
定义,并扩展了上面生成的两个模块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()
这意味着所有子类(无论名称空间如何)都将有一个引用common\models\Order的存在规则
在您的情况下:modules\samplemodule\models\OrderDetail
(使用不同的数据库)将验证是否存在common\models\Order
(来自默认数据库的订单)
下面是我建议的解决方案:
对于common\models\OrderDetail
(生成的类),删除存在性
规则,并在单独的方法中定义它们
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()
方法,我们在前面创建了一个链接,链接到正确的目标类
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']]
];
}
// ..
}
在这两种情况下,我都使用了目标类的全名来帮助突出显示差异,因为它们使用不同的数据库。同一规则不能同时在父类和子类中工作
希望这对你有帮助。祝你好运。你能分享这笔交易的代码吗?你能发布一些代码吗?在尝试获取id之前,是否确保正在调用Model1->save()
?代码处于编辑状态,@csminb是的,我使用save()
函数,否则不会在模块中的模型实例中设置id尝试覆盖OrdersToImport
和OrdersToImportD
的rules()方法,@MarBer在这两个模型中有两个不同的连接?如果是-第二个连接在提交记录之前将看不到记录。我建议您使用getDb()
作为一种方法,使用config中指定的moduleDatabase
配置来分离这两个连接(提供给您的第一个解决方案似乎是实现这一点的最干净的方法)。感谢您的帮助,这个解决方案似乎有效,现在我需要对所有站点组件和模块进行深入测试,以确保所有元素都能像我希望的那样进行交互。我还要感谢你和@Yupik对我的支持!
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']]
];
}
// ..
}