Improve and clarify documentation of callbacks.
This also removes deprecated Events and Callbacks. Closes #1236
This commit is contained in:
@@ -402,10 +402,7 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
|
||||
|
||||
private <T> T triggerAfterConvert(T entity) {
|
||||
|
||||
publisher.publishEvent(new AfterLoadEvent<>(entity));
|
||||
publisher.publishEvent(new AfterConvertEvent<>(entity));
|
||||
|
||||
entity = entityCallbacks.callback(AfterLoadCallback.class, entity);
|
||||
return entityCallbacks.callback(AfterConvertCallback.class, entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ import org.springframework.data.relational.core.mapping.RelationalMappingContext
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
@@ -328,11 +326,9 @@ abstract class JdbcQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
if (entity != null) {
|
||||
|
||||
publisher.publishEvent(new AfterLoadEvent<>(entity));
|
||||
publisher.publishEvent(new AfterConvertEvent<>(entity));
|
||||
|
||||
if (callbacks != null) {
|
||||
entity = callbacks.callback(AfterLoadCallback.class, entity);
|
||||
return callbacks.callback(AfterConvertCallback.class, entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import org.springframework.data.relational.core.mapping.NamingStrategy;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterDeleteCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterSaveCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.BeforeConvertCallback;
|
||||
import org.springframework.data.relational.core.mapping.event.BeforeDeleteCallback;
|
||||
@@ -254,30 +253,6 @@ public class JdbcAggregateTemplateUnitTests {
|
||||
verify(callbacks).callback(AfterDeleteCallback.class, second);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-393
|
||||
public void callbackOnLoad() {
|
||||
|
||||
SampleEntity alfred1 = new SampleEntity(23L, "Alfred");
|
||||
SampleEntity alfred2 = new SampleEntity(23L, "Alfred E.");
|
||||
|
||||
SampleEntity neumann1 = new SampleEntity(42L, "Neumann");
|
||||
SampleEntity neumann2 = new SampleEntity(42L, "Alfred E. Neumann");
|
||||
|
||||
when(dataAccessStrategy.findAll(SampleEntity.class)).thenReturn(asList(alfred1, neumann1));
|
||||
|
||||
when(callbacks.callback(any(Class.class), eq(alfred1), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(alfred2), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann1), any())).thenReturn(neumann2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann2), any())).thenReturn(neumann2);
|
||||
|
||||
Iterable<SampleEntity> all = template.findAll(SampleEntity.class);
|
||||
|
||||
verify(callbacks).callback(AfterLoadCallback.class, alfred1);
|
||||
verify(callbacks).callback(AfterLoadCallback.class, neumann1);
|
||||
|
||||
assertThat(all).containsExactly(alfred2, neumann2);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-101
|
||||
public void callbackOnLoadSorted() {
|
||||
|
||||
@@ -290,16 +265,12 @@ public class JdbcAggregateTemplateUnitTests {
|
||||
when(dataAccessStrategy.findAll(SampleEntity.class, Sort.by("name"))).thenReturn(asList(alfred1, neumann1));
|
||||
|
||||
when(callbacks.callback(any(Class.class), eq(alfred1), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(alfred2), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann1), any())).thenReturn(neumann2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann2), any())).thenReturn(neumann2);
|
||||
|
||||
Iterable<SampleEntity> all = template.findAll(SampleEntity.class, Sort.by("name"));
|
||||
|
||||
verify(callbacks).callback(AfterLoadCallback.class, alfred1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, alfred2);
|
||||
verify(callbacks).callback(AfterLoadCallback.class, neumann1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, neumann2);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, alfred1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, neumann1);
|
||||
|
||||
assertThat(all).containsExactly(alfred2, neumann2);
|
||||
}
|
||||
@@ -316,16 +287,12 @@ public class JdbcAggregateTemplateUnitTests {
|
||||
when(dataAccessStrategy.findAll(SampleEntity.class, PageRequest.of(0, 20))).thenReturn(asList(alfred1, neumann1));
|
||||
|
||||
when(callbacks.callback(any(Class.class), eq(alfred1), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(alfred2), any())).thenReturn(alfred2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann1), any())).thenReturn(neumann2);
|
||||
when(callbacks.callback(any(Class.class), eq(neumann2), any())).thenReturn(neumann2);
|
||||
|
||||
Iterable<SampleEntity> all = template.findAll(SampleEntity.class, PageRequest.of(0, 20));
|
||||
|
||||
verify(callbacks).callback(AfterLoadCallback.class, alfred1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, alfred2);
|
||||
verify(callbacks).callback(AfterLoadCallback.class, neumann1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, neumann2);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, alfred1);
|
||||
verify(callbacks).callback(AfterConvertCallback.class, neumann1);
|
||||
|
||||
assertThat(all).containsExactly(alfred2, neumann2);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.jdbc.core.mapping.AggregateReference;
|
||||
import org.springframework.data.relational.repository.Lock;
|
||||
import org.springframework.data.jdbc.repository.query.Modifying;
|
||||
import org.springframework.data.jdbc.repository.query.Query;
|
||||
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
|
||||
@@ -60,8 +59,8 @@ import org.springframework.data.jdbc.testing.TestConfiguration;
|
||||
import org.springframework.data.jdbc.testing.TestDatabaseFeatures;
|
||||
import org.springframework.data.relational.core.mapping.event.AbstractRelationalEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterConvertEvent;
|
||||
import org.springframework.data.relational.core.mapping.event.AfterLoadEvent;
|
||||
import org.springframework.data.relational.core.sql.LockMode;
|
||||
import org.springframework.data.relational.repository.Lock;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.core.NamedQueries;
|
||||
import org.springframework.data.repository.core.support.PropertiesBasedNamedQueries;
|
||||
@@ -312,7 +311,7 @@ public class JdbcRepositoryIntegrationTests {
|
||||
|
||||
repository.findAllWithSql();
|
||||
|
||||
assertThat(eventListener.events).hasSize(2).hasOnlyElementsOfTypes(AfterLoadEvent.class, AfterConvertEvent.class);
|
||||
assertThat(eventListener.events).hasSize(1).hasOnlyElementsOfType(AfterConvertEvent.class);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-318
|
||||
|
||||
@@ -190,9 +190,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class, //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class //
|
||||
);
|
||||
}
|
||||
@@ -211,9 +209,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class, //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class //
|
||||
);
|
||||
}
|
||||
@@ -231,7 +227,6 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class //
|
||||
);
|
||||
}
|
||||
@@ -250,9 +245,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class, //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class //
|
||||
);
|
||||
}
|
||||
@@ -272,9 +265,7 @@ public class SimpleJdbcRepositoryEventsUnitTests {
|
||||
assertThat(publisher.events) //
|
||||
.extracting(e -> (Class) e.getClass()) //
|
||||
.containsExactly( //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class, //
|
||||
AfterLoadEvent.class, //
|
||||
AfterConvertEvent.class //
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,9 +51,7 @@ public class AbstractRelationalEventListener<E> implements ApplicationListener<A
|
||||
return;
|
||||
}
|
||||
|
||||
if (event instanceof AfterLoadEvent) {
|
||||
onAfterLoad((AfterLoadEvent<E>) event);
|
||||
} else if (event instanceof AfterConvertEvent) {
|
||||
if (event instanceof AfterConvertEvent) {
|
||||
onAfterConvert((AfterConvertEvent<E>) event);
|
||||
} else if (event instanceof AfterDeleteEvent) {
|
||||
onAfterDelete((AfterDeleteEvent<E>) event);
|
||||
@@ -104,20 +102,6 @@ public class AbstractRelationalEventListener<E> implements ApplicationListener<A
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures {@link AfterLoadEvent}.
|
||||
*
|
||||
* @param event will never be {@literal null}.
|
||||
* @deprecated use {@link #onAfterConvert(AfterConvertEvent)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void onAfterLoad(AfterLoadEvent<E> event) {
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("onAfterLoad(%s)", event.getEntity()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures {@link AfterConvertEvent}.
|
||||
*
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.mapping.event;
|
||||
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
|
||||
/**
|
||||
* An {@link EntityCallback} that gets invoked after an aggregate was loaded from the database.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @since 1.1
|
||||
* @deprecated Use {@link AfterConvertCallback} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@FunctionalInterface
|
||||
public interface AfterLoadCallback<T> extends EntityCallback<T> {
|
||||
|
||||
/**
|
||||
* Entity callback method invoked after an aggregate root was loaded. Can return either the same or a modified
|
||||
* instance of the domain object.
|
||||
*
|
||||
* @param aggregate the loaded aggregate.
|
||||
* @return the loaded aggregate.
|
||||
*/
|
||||
T onAfterLoad(T aggregate);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.relational.core.mapping.event;
|
||||
|
||||
/**
|
||||
* Gets published after instantiation and setting of all the properties of an entity. If you want to mutate an entity
|
||||
* after loading, use {@link AfterConvertCallback}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @deprecated Use {@link AfterConvertEvent} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AfterLoadEvent<E> extends RelationalEventWithEntity<E> {
|
||||
|
||||
private static final long serialVersionUID = 7343072117054666699L;
|
||||
|
||||
/**
|
||||
* @param entity the newly instantiated entity. Must not be {@literal null}.
|
||||
*/
|
||||
public AfterLoadEvent(E entity) {
|
||||
super(entity);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,22 @@ package org.springframework.data.relational.core.mapping.event;
|
||||
import org.springframework.data.mapping.callback.EntityCallback;
|
||||
|
||||
/**
|
||||
* An {@link EntityCallback} that gets invoked after an aggregate was saved.
|
||||
* An {@link EntityCallback} that gets invoked after an aggregate was saved to the database.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -19,6 +19,21 @@ import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
|
||||
/**
|
||||
* Gets published after a new instance or a changed instance was saved in the database.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,23 @@ import org.springframework.data.mapping.callback.EntityCallback;
|
||||
/**
|
||||
* An {@link EntityCallback} that gets invoked before the aggregate is converted into a database change. The decision if
|
||||
* the change will be an insert or update is made after this callback gets called.
|
||||
* <p>
|
||||
* This is the correct callback if you want to create Id values for new aggregates.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -18,11 +18,28 @@ package org.springframework.data.relational.core.mapping.event;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
|
||||
/**
|
||||
* Gets published before an aggregate gets converted into a database change.
|
||||
*
|
||||
* Gets published before an aggregate gets converted into a database change, but after the decision was made if an
|
||||
* insert or an update is to be performed.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @since 1.1
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
* @see BeforeConvertCallback
|
||||
*/
|
||||
public class BeforeConvertEvent<E> extends RelationalEventWithEntity<E> {
|
||||
|
||||
|
||||
@@ -21,6 +21,21 @@ import org.springframework.data.relational.core.conversion.MutableAggregateChang
|
||||
/**
|
||||
* An {@link EntityCallback} that gets invoked before changes are applied to the database, after the aggregate was
|
||||
* converted to a database change.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Mark Paluch
|
||||
|
||||
@@ -18,9 +18,25 @@ package org.springframework.data.relational.core.mapping.event;
|
||||
import org.springframework.data.relational.core.conversion.AggregateChange;
|
||||
|
||||
/**
|
||||
* Gets published before an entity gets saved to the database.
|
||||
* Gets published before changes are applied to the database, after the aggregate was converted to a database change.
|
||||
* <p>
|
||||
* The persisting process works as follows:
|
||||
* <ol>
|
||||
* <li>A decision is made, if the aggregate is new and therefore should be inserted or if it is not new and therefore
|
||||
* should be updated.</li>
|
||||
* <li>{@link BeforeConvertCallback} and {@link BeforeConvertEvent} get published.</li>
|
||||
* <li>An {@link org.springframework.data.relational.core.conversion.AggregateChange} object is created for the
|
||||
* aggregate. It includes the {@link org.springframework.data.relational.core.conversion.DbAction} instances to be
|
||||
* executed. This means that all the deletes, updates and inserts to be performed are determined. These actions
|
||||
* reference entities of the aggregates in order to access values to be used in the SQL statements. This step also
|
||||
* determines if the id of an entity gets passed to the database or if the database is expected to generate that id.</li>
|
||||
* <li>{@link BeforeSaveCallback} and {@link BeforeSaveEvent} get published.</li>
|
||||
* <li>SQL statements get applied to the database.</li>
|
||||
* <li>{@link AfterSaveCallback} and {@link AfterSaveEvent} get published.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @see BeforeSaveEvent
|
||||
*/
|
||||
public class BeforeSaveEvent<E> extends RelationalSaveEvent<E> {
|
||||
|
||||
|
||||
@@ -35,14 +35,6 @@ public class AbstractRelationalEventListenerUnitTests {
|
||||
EventListenerUnderTest listener = new EventListenerUnderTest();
|
||||
DummyEntity dummyEntity = new DummyEntity();
|
||||
|
||||
@Test // DATAJDBC-454
|
||||
public void afterLoad() {
|
||||
|
||||
listener.onApplicationEvent(new AfterLoadEvent<>(dummyEntity));
|
||||
|
||||
assertThat(events).containsExactly("afterLoad");
|
||||
}
|
||||
|
||||
@Test // GH-1053
|
||||
public void afterConvert() {
|
||||
|
||||
@@ -125,11 +117,6 @@ public class AbstractRelationalEventListenerUnitTests {
|
||||
events.add("afterSave");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterLoad(AfterLoadEvent<DummyEntity> event) {
|
||||
events.add("afterLoad");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterConvert(AfterConvertEvent<DummyEntity> event) {
|
||||
events.add("afterConvert");
|
||||
|
||||
@@ -848,7 +848,7 @@ class PersonLoadListener extends AbstractRelationalEventListener<Person> {
|
||||
----
|
||||
====
|
||||
|
||||
The following table describes the available events:
|
||||
The following table describes the available events. For more details about the exact relation between process steps see the link:#jdbc.entity-callbacks[description of available callbacks] which map 1:1 to events.
|
||||
|
||||
.Available events
|
||||
|===
|
||||
@@ -865,7 +865,7 @@ The following table describes the available events:
|
||||
This is the correct event if you want to set an id programmatically.
|
||||
|
||||
| {javadoc-base}/org/springframework/data/relational/core/mapping/event/BeforeSaveEvent.html[`BeforeSaveEvent`]
|
||||
| Before an aggregate root gets saved (that is, inserted or updated but after the decision about whether if it gets inserted or updated was made).
|
||||
| Before an aggregate root gets saved (that is, inserted or updated but after the decision about whether if it gets inserted or updated was made). Do not use this for creating Ids for new aggregates. Use `BeforeConvertEvent` or even better `BeforeConvertCallback` instead.
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/AfterSaveEvent.html[`AfterSaveEvent`]
|
||||
| After an aggregate root gets saved (that is, inserted or updated).
|
||||
@@ -883,35 +883,43 @@ WARNING: Lifecycle events depend on an `ApplicationEventMulticaster`, which in c
|
||||
[[jdbc.entity-callbacks]]
|
||||
=== Store-specific EntityCallbacks
|
||||
|
||||
Spring Data JDBC uses the `EntityCallback` API for its auditing support and reacts on the following callbacks:
|
||||
Spring Data JDBC uses the `EntityCallback` API for its auditing support and reacts on the callbacks listed in the following table.
|
||||
|
||||
.Available Callbacks
|
||||
.Process Steps and Callbacks of the Different Processes performed by Spring Data JDBC.
|
||||
|===
|
||||
| `EntityCallback` | When It Is Published
|
||||
| Process | `EntityCallback` / Process Step | Comment
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/BeforeDeleteCallback.html[`BeforeDeleteCallback`]
|
||||
| Before an aggregate root gets deleted.
|
||||
.3+| Delete | {javadoc-base}org/springframework/data/relational/core/mapping/event/BeforeDeleteCallback.html[`BeforeDeleteCallback`]
|
||||
| Before the actual deletion.
|
||||
|
||||
2+| The aggregate root and all the entities of that aggregate get removed from the database.
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/AfterDeleteCallback.html[`AfterDeleteCallback`]
|
||||
| After an aggregate root gets deleted.
|
||||
| After an aggregate gets deleted.
|
||||
|
||||
.6+| Save 2+| Determine if an insert or an update of the aggregate is to be performed dependen on if it is new or not.
|
||||
|
||||
| {javadoc-base}/org/springframework/data/relational/core/mapping/event/BeforeConvertCallback.html[`BeforeConvertCallback`]
|
||||
| Before an aggregate root gets converted into a plan for executing SQL statements, but after the decision was made if the aggregate is new or not, i.e. if an update or an insert is in order.
|
||||
This is the correct callback if you want to set an id programmatically.
|
||||
| This is the correct callback if you want to set an id programmatically. In the previous step new aggregates got detected as such and a Id generated in this step would be used in the following step.
|
||||
|
||||
2+| Convert the aggregate to a aggregate change, it is a sequence of SQL statements to be executed against the database. In this step the decision is made if an Id is provided by the aggregate or if the Id is still empty and is expected to be generated by the database.
|
||||
|
||||
| {javadoc-base}/org/springframework/data/relational/core/mapping/event/BeforeSaveCallback.html[`BeforeSaveCallback`]
|
||||
| Before an aggregate root gets saved (that is, inserted or updated but after the decision about whether if it gets inserted or updated was made).
|
||||
| Changes made to the aggregate root may get considered, but the decision if an id value will be sent to the database is already made in the previous step.
|
||||
|
||||
2+| The SQL statements determined above get executed against the database.
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/AfterSaveCallback.html[`AfterSaveCallback`]
|
||||
| After an aggregate root gets saved (that is, inserted or updated).
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/AfterLoadCallback.html[`AfterLoadCallback`]
|
||||
| After an aggregate root gets created from a database `ResultSet` and all its property get set. _This is deprecated, use `AfterConvertCallback` instead_
|
||||
.2+| Load 2+| Load the aggregate using 1 or more SQL queries. Construct the aggregate from the resultset.
|
||||
|
||||
| {javadoc-base}org/springframework/data/relational/core/mapping/event/AfterConvertCallback.html[`AfterConvertCallback`]
|
||||
| After an aggregate root gets created from a database `ResultSet` and all its property get set.
|
||||
|
|
||||
|===
|
||||
|
||||
We encourage the use of callbacks over events since they support the use of immutable classes and therefore are more powerful and versatile than events.
|
||||
|
||||
include::{spring-data-commons-docs}/entity-callbacks.adoc[leveloffset=+1]
|
||||
|
||||
include::jdbc-custom-conversions.adoc[]
|
||||
|
||||
Reference in New Issue
Block a user