Transactions Yii2数据库事务上存在验证规则

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

我的模型中的一个函数使用事务将行保存在两个不同的表中,即表1和表2。在表_2中,一个外键指的是表_1.id,由gii自动生成的验证规则为“存在”类型。当我需要保存行时,第一步是开始一个数据库事务,第二步是设置并保存一个表_1行,最后设置并保存与表_1行相关的表_2行,如果两个insert都正常,则事务是commit else rollback。问题是,当我将表_1行的id传递给表_2时,验证失败,因为表_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();
}
是:

这些都是从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']]
        ];
    }
    // ..
}