spring-projects / spring-data-cassandra

Provides support to increase developer productivity in Java when using Apache Cassandra. Uses familiar Spring concepts such as a template classes for core API usage and lightweight repository style data access.
https://spring.io/projects/spring-data-cassandra/
Apache License 2.0
374 stars 307 forks source link

`ReactiveBeforeSaveCallback` not documented properly #1448

Closed amazingstream closed 8 months ago

amazingstream commented 8 months ago

ReactiveBeforeSaveCallback is not persisting the transformed object to the database but the save method returns the transformed object.

I am using version 3.4.16. I implemented ReactiveBeforeSaveCallback like this...

import org.springframework.data.cassandra.core.mapping.event.ReactiveBeforeSaveCallback; import reactor.core.publisher.Mono;

public class CustomReactiveBeforeSaveCallback implements ReactiveBeforeSaveCallback {

@Override
public Mono<MyType> onBeforeSave(MyType entity, String tableName) { 
    entity.setColumnValue("CHANGED VALUE...");
    return Mono.just(entity);
}

}

MyType n = new MyType(); n.setColumnValue("ORIGINAL");

I am calling the save method like this.

Mono saved = reactiveEntityRepository.save(n); saved.subscribe(s -> System.out.println(s.columnValue); //returns CHANGED VALUE but the database has ORIGINAL

);

saved.columnValue has "CHANGED VALUE". But the database still has "ORIGINAL". I was expecting the database to persist the transformed value. I can see that the before save method is being invoked but the updated value is not being stored to the database.

mp911de commented 8 months ago

BeforeSaveCallback is called after transforming the object into a Statement (that's also why you get the Statement object). Before save is useful if you want to save a certain state to the database but you want to render a different object state after the save.

What you're looking for is ReactiveBeforeConvertCallback.

Looking at the documentation, the docs of events and callbacks could be a bit more descriptive and so I'm converting this ticket into a documentation ticket.

amazingstream commented 8 months ago

Thanks for the quick response. Changing ReactiveBeforeSaveCallback to ReactiveBeforeConvertCallback worked for me.

amazingstream commented 8 months ago

why is ReactiveAfterConvertCallback or afterLoadCallback not available? I am able to transform the entity before persisting using ReactiveBeforeConvertCallback but I have to transform again after reading from the database.

Should I be using a different interface?

mp911de commented 8 months ago

ReactiveAfterConvertCallback isn't available as the entity row mapper doesn't expose a reactive mapping interface. Also, bulk-loading entities and creating Mono's creates a lot of GC pressure so we initially didn't want to expose a reactive AfterLoad/AfterConvert callback.

amazingstream commented 8 months ago

I see. Initially, I implemented PropertyValueConverter and added @ValueConverter to a property before persisting. But that is also not getting invoked.

I understand @ValueConverter is part of spring data and I am using Spring data reactive cassandra.

@Table("tablename") public class TestTableClass{

@ValueConverter(..class)

mp911de commented 8 months ago

Thanks for bringing @ValueConverter up. It isn't supported yet and I created #1449 to keep track of the progress.