Magento2 database transactions: how to save multiple model instances

Sometimes in your logic you have to save different model instances at once.

Magento1 already had the concept of transaction, using the classic singleton model:

Mage::getModel('core/resource_transaction')

Magento2 has its concept of transaction, too, so let’s see with a simple example how to use this feature.

Let’s say we have a DB table ‘table’ described as follows:

 

+-----+--------+--------+
| id  | field1 | field2 |
+-----+--------+--------+

We’ll have a \Some\Thing\Model\Table:

class Table extends \Magento\Framework\Model\AbstractModel implements \Magento\Framework\DataObject\IdentityInterface {
  [..]
  public function __construct(
    \Magento\Framework\Model\Context $context,
    \Magento\Framework\Registry $registry,
    \Some\Thing\Model\ResourceModel\Table $resource,
    \Some\Thing\Model\ResourceModel\Table\Collection $resourceCollection,
    array $data = []
 ) {
    parent::__construct($context, $registry, $resource, $resourceCollection, $data);
 }
 [..]
}

And a classic \Some\Thing\Model\ResourceModel\Table that looks like this:

class Table extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb
{
   /**
    * Set main entity table name and primary key field name
    *
    * @return void
   */
   protected function _construct()
   {
      $this->_init('table', 'id');
   }
}

So, let’s say that in our controller or API call we want to save different Tables at once.

In the constructor we have to make clear some dependencies:

public function __construct(
 [..]
 \Some\Thing\Model\TableFactory $tableFactory,
 \Magento\Framework\DB\TransactionFactory $transactionFactory
 ) {
  [..]
  $this->tableFactory = $tableFactory;
  $this->transactionFactory = $transactionFactory;
}

 

  • adsense



  • In our logic there will be something like this:

    $transaction = $this->transactionFactory->create();
    foreach ($values as $field1 => $field2) {
      $tableInstance = $this->tableFactory->create();
      $tableInstance->setField1($field1);
      $tableInstance->setField2($field2);
      $transaction->addObject($tableInstance);
    }
    $transaction->save();

    So, at first we create a transaction instance from the transaction factory.
    Then, in each iteration in the foreach loop we create a table instance from the Table factory.

    We set all the required fields and then we add the instance to the transaction.

    The last step is to call the save() method of the transaction instance to save all the Table instances.

    Please note that, in case of errors, Magento2 performs a rollback:

    // Magento\Framework\DB\Transaction::save()#L143:L148
    if ($error) {
      $this->_rollbackTransaction();
      throw $error;
    } else {
      $this->_commitTransaction();
    }

     

    Leave a Comment

    Your email address will not be published. Required fields are marked *