go-gorm / optimisticlock

optimistic lock plugin for gorm
MIT License
88 stars 16 forks source link

Optimistic lock for associations when FullSaveAssociations is enabled #29

Closed arsmn closed 9 months ago

arsmn commented 11 months ago

Your Question

When FullSaveAssociations is enabled and an association is updated, the generated query is not modified by this plugin and therefore locking is not working even though version field is available for that association. Is there any possible solution for this? (except disabling FullSaveAssociations)

The document you expected this should be explained

Expected answer

icpd commented 10 months ago

Could you please share some sample code for testing purposes?

arsmn commented 10 months ago

Hi @icpd Consider these two models:

type User struct {
    ID        uint64                 `gorm:"primary_key;column:id"`
    FirstName string                 `gorm:"type:varchar(100);column:first_name"`
    LastName  string                 `gorm:"type:varchar(100);column:last_name"`
    Orders    []*Order               `gorm:"many2many:user_orders"`
    Version   optimisticlock.Version `gorm:"type:bigint;column:version"`
}

type Order struct {
    ID      uint64                 `gorm:"primary_key;column:id"`
    Amount  int64                  `gorm:"type:bigint,column:amount"`
    Version optimisticlock.Version `gorm:"type:bigint;column:version"`
}

User is fetched preloaded with order association:

u := User{
    ID:        1000,
    FirstName: "aaa",
    LastName:  "bbb",
    Orders:    []*Order{
        {
            ID:      2000,
            Amount:  5000,
            Version: optimisticlock.Version{
                Int64: 1,
                Valid: true,
            },
        },
    },
    Version:   optimisticlock.Version{
        Int64: 1,
        Valid: true,
    },
}

Updating the order

u.Orders[0].Amount = 6000
db.Session(&gorm.Session{FullSaveAssociations: true}).Table(TableNameUser).Updates(&u)

Will generate these queries

INSERT INTO "orders" ("id","amount","version") VALUES (2000,'6000',1) ON CONFLICT ("id") DO UPDATE SET "amount"="excluded"."amount","version"="excluded"."version"

INSERT INTO "user_orders" ("user_id","order_id") VALUES (1000,2000) ON CONFLICT DO NOTHING

UPDATE "persons" SET UPDATE "users" SET "id"=1000,"first_name"='4321',"last_name"='1234',"version"="version"+1 WHERE "persons"."version" = 1 AND "id" = 1000

The first query to update the order association does not have version condition clause (and increase in case of update) and will be overwritten with the model value.

icpd commented 10 months ago

Unfortunately, INSERT INTO ... ON ... UPDATE ... is a INSERT statement, so there is no way to achieve the expected results you want.

arsmn commented 9 months ago

Thanks @icpd