grails / gorm-mongodb

GORM for MongoDB
Apache License 2.0
69 stars 31 forks source link

Can't refresh domain class instance from the database in statefull mode #147

Open yagotlima opened 4 years ago

yagotlima commented 4 years ago

I'm creating this issue after failing to find a solution from Stackoverflow.

Since the refresh method is not implemented on Gorm for Mongo and the method get(id) would return the same cached instance, is it possible to refresh a domain class instance from the database?

sagrawal31 commented 2 years ago

Any update here?

yagotlima commented 2 years ago

Any update here?

Hi. Unfortunately no. I managed to fix that project by managing concurrency in Java itself. My Stack Overflow post was deleted for some reason. I can paste it here if you want more details.

sagrawal31 commented 2 years ago

Thanks, @yagotlima. Please paste it here and share the link as well.

yagotlima commented 2 years ago

Thanks, @yagotlima. Please paste it here and share the link as well.

My original Stack Overflow question was:

How to refresh object from database unsing GORM for MongoDB?

I have a Grails application using mongoDB that runs a long piece of code that updates a domain class at the end. Since this piece of code runs concurrently I'm gatting a lot of OptimisticLockingExceptions.

To avoid that I decide to do as following:

def method(Vehicle vehicle) {
    // long read only code using vehicle's properties

    synchronyzed(lock) {
        vehicle.refresh()
        vehicle.property = newValue
        vehicle.save()
    }
}

Unfortunatelly the refresh method is not implemented on GORM for MongoDB and throws java.lang.UnsupportedOperationException: Refresh not supported by codec entity persistence engine.

I also tried the following:

def method(Vehicle vehicle) {
    // long read only code using vehicle's properties

    synchronyzed(lock) {
        vehicle = Vehicle.get(vehicle.id)
        vehicle.property = newValue
        vehicle.save()
    }
}

But looks like there is some sort of session that returns the same object like Hibernate's L1 cache would.

Is there a way to refresh this instance?

PS: I'm aware I can switch the class to stateless mode but that would require a huge refactor and stateful mode is just better for my use case except for this piece of code.

sagrawal31 commented 2 years ago

So far, the need of refresh() was only coming in our integration tests. For that, we are doing this-

Vehicle vehicleInstance // some existing instance

Vehicle.withNewSession {
    vehicleInstance = Vehicle.get(vehicleInstance.id)
}

We further made this DRY in our base abstract test file by adding a method-

GormEntity refreshInstance(GormEntity instance) {
    // Flushing to get persist it to DB immediately
    instance.save(flush: true)

    UserOrAnyDomain.withNewSession {
        return instance.class.get(instance.id)
    }
}

and then calling directly-

Vehicle vehicleInstance // some existing instance

vehicleInstance = refreshInstance(vehicleInstance)
yagotlima commented 2 years ago

I think Vehicle.withNewSession { vehicleInstance = Vehicle.get(vehicleInstance.id) } is exactly what I was looking for back then. Even though we managed to work around this problem, it's great to know how to deal with it moving forward. Thank you.

sagrawal31 commented 2 years ago

Thanks, @yagotlima. I would like to keep this issue open so that the GORM team can implement it natively.

yagotlima commented 2 years ago

@sagrawal31 sorry for that