Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Active Record Optimistic locking does not work with multiple models #16889

Open
Webkadabra opened this issue Nov 14, 2018 · 18 comments
Open

Active Record Optimistic locking does not work with multiple models #16889

Webkadabra opened this issue Nov 14, 2018 · 18 comments
Labels
feature:db status:to be verified Needs to be reproduced and validated. type:bug Bug

Comments

@Webkadabra
Copy link

Webkadabra commented Nov 14, 2018

What steps will reproduce the problem?

Controller code:

if (Model::loadMultiple($models, Yii::$app->request->post()) && Model::validateMultiple($models)) {
            $count = 0;
            foreach ($models as $index => $modelIN) {
                if ($modelIN->save()) {
                    $count++;
                }
            }
        }

Controller gets POST input:

  Array
  (
  [_csrf] => plOgdUA529aMw6mz-uan96qT-1Ty2NS2KbTasCtqK-LVHPpHK363--aB7di_it-23uuDLsP1neBuwIyCSC942g==
  [ShopItem] => Array
  (
  [lock_version] => 1
  [product_type] => group
  [frontend_name] => Main product name
  [sku] => 3904-G
  [available_yn] => 1
  ...
  [55] => Array
  (
  [id] => 55
  [lock_version] => 3
  [frontend_name] => Included product name
  [sku] => 9838
  [in_stock_yn] => 1
  [stock_available] => 1
  [price] => 98.00
  [old_price] => 106.00
  )
   
  )
  )
-- --
   

What is the expected result?

All items should be updated correctly given they are not outdated

What do you get instead?

yii\db\StaleObjectException: The object being updated is outdated. in

Copy Stacktrace Search Stackoverflow Search Google Exception
Stale Object Exception – yii\db\StaleObjectException
The object being updated is outdated.

Additional info

Q A
Yii version 2.0.15.1
PHP version 7.2.10
Operating system Win 7 (x64)
@samdark samdark added type:bug Bug status:to be verified Needs to be reproduced and validated. feature:db labels Nov 14, 2018
@strtob
Copy link

strtob commented Mar 25, 2019

I have the same problem when I use yii2-relation-trait (mootensai/yii2-relation-trait#60)

:-( any help?

@Webkadabra
Copy link
Author

@strtob Laravel... JK. Honestly, I had no luck fixing this

@strtob
Copy link

strtob commented Apr 8, 2019

Thank you for your efforts, that's really a shame. This is a basic functionality (save realted records after a first validation error) and without fixing this in near future, I'll need to rewrite my project with laravel or some other php framework... :-(

@Webkadabra
Copy link
Author

@strtob I think in one of my projects I "fixed" this doing the following: just disable optimistic lock behavior before you save model, then do $this->updateCounters(...) ti update lock version for each model after save.

This is an issue for loading multiple models. Working with a single model is working fine

@isan26
Copy link

isan26 commented Apr 8, 2019

@strtob changing to Laravel Will bring you more problema,i'm using it in my job and i don't recomendet..read and seek for a solution instead of just surrender

@Webkadabra
Copy link
Author

Guys, I'm dabbling in comedy so Laravel was a joke. I don't understand why would anyone jump from Yii2 to any other PHP framework.

@Webkadabra
Copy link
Author

We need to summon the great @samdark

@strtob
Copy link

strtob commented Apr 8, 2019

...thanks to share your experience with laravel. In general I'm happy with yii2, but when the app will throw the error furthermore, a normal use can't handle this :-( I will try the $this->updateCounters(...) and hope this will fix the problem

@isan26
Copy link

isan26 commented Apr 8, 2019 via email

@Webkadabra
Copy link
Author

Yii2 till I die! Really, I'm working on a big project of my own right now, and if it won't be successful then I'm gonna kill myself

@isan26
Copy link

isan26 commented Apr 8, 2019 via email

@Webkadabra
Copy link
Author

@isan26 I'm super broke and spending my time developing a SaaS solution for Ukrainian market. It is very counter-intuitive to do anything for Ukrainian market

@isan26
Copy link

isan26 commented Apr 8, 2019 via email

@Webkadabra
Copy link
Author

You'd think.... 😆

@isan26
Copy link

isan26 commented Apr 8, 2019 via email

@Webkadabra
Copy link
Author

@isan26 if you have some job that pays doing whatever yii2, I'd love to join.

@samdark
Copy link
Member

samdark commented Apr 10, 2019

@Webkadabra tried debugging it? Any idea why it happens? Does actual table schema/model code matters? Could it be reproduced with data-less model with only a few fields and Gii-generated code? What's DB engine?

@strtob
Copy link

strtob commented Mar 26, 2022

this is a solution (shorten) I use in my controller, maybe this will help someone.

In first case of conflict, the user will get a message that the next update will overwrite the newest request:

public function actionUpdate($id) {

        /* PREPARE DATA */
        $model = $this->findModel($id);    

        /* Load and validate Model */
        if ($model->loadAll(Yii::$app->request->post()) && $model->validate()) {

            /* Try to save model */
            if ($model->saveAll([])
            ) {

                return $this->redirect(['update', 'id' => $model->id]);
            }
        } else {

            
            // check if lock error
            if (($model->getErrors('db_lock')) != null) {
                \Yii::$app->getSession()->setFlash('warning',
                        yii::t('app', 'Your data are behind of data from {username} - your next UPDATE will overwrite with your data or you will be overwritten!', [
                            'username' => \app\models\User::findOne($model->updated_by)->getNameFormal(),
                            'version' => $model->db_lock,
                ]));

                $model->db_lock = $model->db_lock + 1;
                // relation has entries? --> then also increment - next update wil overrule!
                foreach ($model->relatedRecords as $name => $records) {

                    if (($model->$name)) {
                        foreach($model->$name as $relatedModel)
                        {                            
                            if(isset($relatedModel->db_lock))                      
                            $relatedModel->db_lock = $relatedModel->db_lock + 1;
                        }                        
                    }
                }                
            }
        }

            return $this->render('update', [
                        'model' => $model,                    
            ]);
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature:db status:to be verified Needs to be reproduced and validated. type:bug Bug
Projects
None yet
Development

No branches or pull requests

4 participants