0

我的模型中的一个函数使用事务将行保存在两个不同的表 table_1 和 table_2 中。在 table_2 中,一个外键引用 table_1.id 并且由 gii 自动生成的验证规则是类型“exist”。当我需要保存行时,第一步是开始数据库事务,第二步是设置并保存 table_1 行,最后设置并保存与 table_1 行相关的 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." } }
4

1 回答 1

0

这些是从gii生成的,我想这样生成的所有规则都是正确的

是的,规则是正确的,并且在大多数用例中都很好。
并不意味着它们适用于所有情况

我从评论中假设您的结构是这样的:(
如果我错了,请使用适当的详细信息更新您的问题):为简单起见,
我将它们称为OrderOrderDetail

  • 生成的模型:这些包含existance您提到的规则 common\models\Order
    common\models\OrderDetail

  • 具有自定义数据库的模型:这些包含对getDb()上面两个生成的模块的不同定义和扩展
    common\modules\samplemodule\models\Order
    common\modules\samplemodule\models\OrderDetail

现在模型中的模型samplemodule将继承生成模型的规则。

请注意targetClass以下生成的规则common\models\OrderDetail

[['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(来自默认数据库的订单)


所以这是我提出的解决方案:

for common\models\OrderDetail(生成的类)删除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()我们之前创建的方法链接正确的目标类

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']]
        ];
    }
    // ..
}

在这两种情况下,我都使用了目标类的全名来帮助突出差异,因为它们使用不同的数据库,相同的规则在父类和子类中都不起作用。

希望这对你有帮助。祝你好运。

于 2017-07-21T08:18:37.000 回答