Db Transactional Operation

Hi,

I understood you included some transactional features in AR, but I’m not sure how we are supposed to use it.

For example, I want to log all operations on some table in a shadow table.

For instance, all operations (insert and update) in tbl_project must be log in tbl_project_history.

I wan’t a generic method for all tables with a history table.

Do I have to extend ActiveRecord with a new save method ?

Another way to do it ?

You can read the Transactional Operations section of the Yii2 ActiveRecord Doc/Guide.

I am not sure this requires transactional operation, but you may extend ActiveRecord and write your own AppActiveRecord that you can use as a generic base and extend all other models. For example

Your Base Model




namespace app\models;


class AppActiveRecord extends \yii\db\ActiveRecord {

    /* The history table */

    public $history;


    public function populateHistory() {

        $attributes = $this->$attributes;

        // Insert validations and populate into $this->history

    }


    public function beforeSave($insert) {

        $this->populateHistory();

        return parent::beforeSave($insert);

    }

}



Your other models can extend this class. For example for Project Model:




namespace app\models;


class Project extends AppActiveRecord {

    public $history = 'tbl_project_history';


    public static function tableName() {

        return 'tbl_project';

    }


    /* Other operations */

}



Many thanks for your reply.

I just put an example (could be more tricky…), but the idea is I don’t want to save a project row if the related history row is not saved, and I don’t want to save a history row if project row commit fails.

That is why, to be clean, I need a transactional operation.

Your example is interesting, but not really a transactional operation. If project commit fails, I could have a dummy history row.

I need a rollback mechanism.

I looked at the documentation, but it seems incomplete, or I did not understand…

You could do model level validation before you save the record to any database without the need for transactional operations. Something like:




   if ($model->validate()) {   // project model

       $history = $model->fetchHistory(); // a custom function to populate history for the model

       if ($history->validate()) { // $history is the history model

           $model->save();

           $history->save();

       }

       else {

          echo "History population failed dude!"; // use $history->getErrors();

       }

   }

   else {

      echo "Project population failed dude!"; // use $model->getErrors();

   }



If you still want to play directly with database tables, you can use transactional operations. But then you typically do not need Yii2 AR models and in this case you lose the AR validation rules and functionality of yii.

I think that for a reliable application, you generally need transactions.

A database update can fail for various reasons (not only functional rules) : table lock, database crash, network issue, …

If two database operations are tightly linked, the only way to guarantee data consistency is transactions.

Could be a significant enhancement…

Yes I get you… your query is probably being addressed in Yii2 - AR Transactional Operations. You probably need to use atomic scenarios and operations feature, as mentioned in the docs. But, read carefully, on how the approach is to be carefully/correctly used - as loading such validations in controller is a not recommended approach. Yes, the documentation is incomplete, but should give you some idea. I would suggest, you have a look at the code of AR to achieve this. Have not yet used this myself in Yii2… but will put up some examples when I do get time. In case you do get some headstart on this… do update :) for others’ benefit.