Yii2 使用存储过程保存到多个表中

Yii2 使用存储过程保存到多个表中,yii2,Yii2,我有两种型号:receivedGoodDetail和StockInventory 当modelReceivedGoodDetailDoActionCreate时,StockInventory也会自动插入表StockInventory 我使用这个存储过程,这是我尝试过的: public function actionCreate($id) { $model = new ReceivedGoodsDetail(); $connection = \Yii::$app->db; $transact

我有两种型号:
receivedGoodDetail
StockInventory

当model
ReceivedGoodDetail
DoActionCreate时,
StockInventory
也会自动插入表
StockInventory

我使用这个存储过程,这是我尝试过的:

public function actionCreate($id) {
$model = new ReceivedGoodsDetail();
$connection = \Yii::$app->db;
$transaction = $connection->beginTransaction();

$model->ID_Received_Goods = $id;
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$connection = Yii::$app->db;
$command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');

$ID_Received_Goods = $model->ID_Received_Goods;

$ID_Item = $model->ID_Item;
$Qty = $model->Qty;
$User = Yii::$app->user->identity->username;

$command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
$command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
$command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
$command->bindParam(":User", $User, PDO::PARAM_STR);

if ($command->execute() == 0) {
$transaction->commit();
} else {
$transaction->rollBack();
foreach ($model->getErrors() as $key => $message) {
Yii::$app->session->setFlash('error', $message);
}
}

return $this->redirect(['receivedgoodsheader/view', 'id' =>    $model->ID_Received_Goods]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}

但是,如果使用上述两种模型,我会感到困惑。不要害怕这样做,这里使用存储过程并没有什么不好的。但一般来说,您的代码并不干净,也不容易理解

首先,如果您使用的是存储过程,那么为什么不为ReceivedGoodDetail(在Insert上)创建一个触发器呢?我想用触发器一切都会简单得多

下面是一些关于您的实现的评论

  • 如果,为什么在第一次
    之前打开交易?如果验证失败,您的交易将不会关闭
    手动
  • 我看不出这里使用了两种型号,只有一种-
    receivedGoodDetail
    ,和
    StockInventory
    据我所知,将在存储过程
    usp_T_Received_Goods_Detail#InsertData
    中创建
  • 为什么即使事务失败也要将用户重定向到项目视图
  • 使用ActiveRecord。这样就不需要手动启动事务。只需定义什么操作 您希望此模型在方法中具有事务性
  • 使用ActiveRecord。更好的做法是从模型类而不是应用程序获取db连接。 默认情况下,它将是
    Yii::$app->db
    ,但稍后您可以轻松更改此特定型号的连接
  • 例如,您最好扩展ActiveRecord(如果还没有)并重载
    insertInternal()
    方法 对于
    receivedGoodDetail

    在类
    receivedGoodDetail
    中:

    public function transactions() {
        return [
            'default' => self::OP_INSERT
        ];    
    }
    
    protected function insertInternal($attributeNames = null) {
        if (!$this->beforeSave(true)) {
            return false;
        }
        $values = $this->getDirtyAttributes($attributes);
    
        /* overrided part of code */
    
        $connection = static::getDb();
        $command = $connection->createCommand('{call usp_T_Received_Goods_Detail#InsertData(:ID_Received_Goods,:ID_Item, :Qty, :User)}');
    
        $ID_Received_Goods = $model->ID_Received_Goods;
    
        $ID_Item = $model->ID_Item;
        $Qty = $model->Qty;
        $User = Yii::$app->user->identity->username;
    
        $command->bindParam(":ID_Received_Goods",$ID_Received_Goods,PDO::PARAM_STR);
        $command->bindParam(":ID_Item", $ID_Item, PDO::PARAM_STR);
        $command->bindParam(":Qty", $Qty, PDO::PARAM_INT);
        $command->bindParam(":User", $User, PDO::PARAM_STR);
    
        if($command->execute() != 0) {
            return false;
        }
    
        /* end of overrided part */
    
        $changedAttributes = array_fill_keys(array_keys($values), null);
        $this->setOldAttributes($values);
        $this->afterSave(true, $changedAttributes);
    
        return true;
    }
    
    在你的行动中:

    public function actionCreate($id) {
        $model = new ReceivedGoodsDetail();
    
        $model->ID_Received_Goods = $id;
        if ($model->load(Yii::$app->request->post()) && $model->save(true)) {
            return $this->redirect(['receivedgoodsheader/view', 'id' => $model->ID_Received_Goods]);
        } else {
            foreach ($model->getErrors() as $key => $message) {
                Yii::$app->session->setFlash('error', $message);
            }
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }
    
    然后在创建表单上捕获您的flash消息

    还有一分钟。使用
    path/to/model/{id}
    endpoint是一种奇怪的做法 使用预定义的
    ID
    创建新实例。通常这看起来像
    POST path/to/model
    。但这可能是您的业务逻辑的主题,所以我不知道是否可以改进


    p.p.S.这个例子没有经过测试(显然),所以这里可能有一些错误

    你有什么问题?我不明白