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

时间:2016-07-15 10:09:06

标签: yii2

我有2个模型:ReceivedGoodsDetailStockInventory

当模型ReceivedGoodsDetail执行actionCreate时,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,
]);
}
}

但是如果像上面的情况一样使用2个模型我很困惑

1 个答案:

答案 0 :(得分:0)

不要害怕做这样的事情,这里使用存储过程没什么不好。但总的来说,你的代码并不干净,令人困惑。

首先,如果您正在使用存储过程,那么为什么不为ReceivedGoodsDetail(在INSTERT上)触发?恕我直言,触发器的一切都会简单得多。

以下是您实施的一些评论。

  1. 为什么在第一次if之前打开交易?如果验证失败,那么您的交易将不会被关闭 手动。
  2. 我在这里看不到使用2个模型,只有一个 - ReceivedGoodsDetailStockInventory 我能理解的将在存储过程中创建usp_T_Received_Goods_Detail#InsertData
  3. 为什么即使交易失败,您也会将用户重定向到项目视图?
  4. 使用ActiveRecord。那么这里不需要手动启动事务。只需定义哪些操作 您希望在transactions()方法中对此模型进行交易。
  5. 使用ActiveRecord。最好从模型类而不是应用程序获取数据库连接。 默认情况下它为Yii::$app->db,但稍后您可以轻松更改此特定模型的连接。
  6. 最好(例如)扩展ActiveRecord(如果还没有)并重载insertInternal()方法 为ReceivedGoodsDetail

    在课程ReceivedGoodsDetail中:

    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消息。

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

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