30
30
import org .springframework .beans .BeansException ;
31
31
import org .springframework .beans .factory .BeanFactory ;
32
32
import org .springframework .beans .factory .BeanFactoryAware ;
33
+ import org .springframework .core .convert .ConversionService ;
33
34
import org .springframework .dao .DataAccessException ;
34
35
import org .springframework .dao .TransientDataAccessResourceException ;
35
36
import org .springframework .data .mapping .IdentifierAccessor ;
36
37
import org .springframework .data .mapping .MappingException ;
38
+ import org .springframework .data .mapping .PersistentPropertyAccessor ;
37
39
import org .springframework .data .mapping .context .MappingContext ;
38
40
import org .springframework .data .projection .ProjectionInformation ;
39
41
import org .springframework .data .projection .SpelAwareProxyProjectionFactory ;
58
60
* prepared in an application context and given to services as bean reference.
59
61
*
60
62
* @author Mark Paluch
63
+ * @author Bogdan Ilchyshyn
61
64
* @since 1.1
62
65
*/
63
66
public class R2dbcEntityTemplate implements R2dbcEntityOperations , BeanFactoryAware {
@@ -372,6 +375,8 @@ <T> Mono<T> doInsert(T entity, SqlIdentifier tableName) {
372
375
373
376
RelationalPersistentEntity <T > persistentEntity = getRequiredEntity (entity );
374
377
378
+ setVersionIfNecessary (persistentEntity , entity );
379
+
375
380
return this .databaseClient .insert () //
376
381
.into (persistentEntity .getType ()) //
377
382
.table (tableName ).using (entity ) //
@@ -380,6 +385,24 @@ <T> Mono<T> doInsert(T entity, SqlIdentifier tableName) {
380
385
.defaultIfEmpty (entity );
381
386
}
382
387
388
+ private <T > void setVersionIfNecessary (RelationalPersistentEntity <T > persistentEntity , T entity ) {
389
+ PersistentPropertyAccessor <?> propertyAccessor = persistentEntity .getPropertyAccessor (entity );
390
+ RelationalPersistentProperty versionProperty = persistentEntity .getVersionProperty ();
391
+
392
+ if (versionProperty == null ) {
393
+ return ;
394
+ }
395
+
396
+ Object currentVersionValue = propertyAccessor .getProperty (versionProperty );
397
+ if (currentVersionValue != null ) {
398
+ return ;
399
+ }
400
+
401
+ Class <?> versionPropertyType = versionProperty .getType ();
402
+ ConversionService conversionService = this .dataAccessStrategy .getConverter ().getConversionService ();
403
+ propertyAccessor .setProperty (versionProperty , conversionService .convert (1L , versionPropertyType ));
404
+ }
405
+
383
406
/*
384
407
* (non-Javadoc)
385
408
* @see org.springframework.data.r2dbc.core.R2dbcEntityOperations#update(java.lang.Object)
@@ -391,11 +414,19 @@ public <T> Mono<T> update(T entity) throws DataAccessException {
391
414
392
415
RelationalPersistentEntity <T > persistentEntity = getRequiredEntity (entity );
393
416
394
- return this .databaseClient .update () //
417
+ DatabaseClient . UpdateMatchingSpec updateMatchingSpec = this .databaseClient .update () //
395
418
.table (persistentEntity .getType ()) //
396
- .table (persistentEntity .getTableName ()).using (entity ) //
397
- .fetch ().rowsUpdated ().handle ((rowsUpdated , sink ) -> {
419
+ .table (persistentEntity .getTableName ()) //
420
+ .using (entity );
421
+
422
+ DatabaseClient .UpdateSpec updateSpec = updateMatchingSpec ;
423
+ if (persistentEntity .hasVersionProperty ()) {
424
+ updateSpec = updateMatchingSpec .matching (createMatchingVersionCriteria (entity , persistentEntity ));
425
+ incrementVersion (entity , persistentEntity );
426
+ }
398
427
428
+ return updateSpec .fetch () //
429
+ .rowsUpdated ().handle ((rowsUpdated , sink ) -> {
399
430
if (rowsUpdated == 0 ) {
400
431
sink .error (new TransientDataAccessResourceException (
401
432
String .format ("Failed to update table [%s]. Row with Id [%s] does not exist." ,
@@ -406,6 +437,33 @@ public <T> Mono<T> update(T entity) throws DataAccessException {
406
437
});
407
438
}
408
439
440
+ private <T > void incrementVersion (T entity , RelationalPersistentEntity <T > persistentEntity ) {
441
+ PersistentPropertyAccessor <?> propertyAccessor = persistentEntity .getPropertyAccessor (entity );
442
+ RelationalPersistentProperty versionProperty = persistentEntity .getVersionProperty ();
443
+
444
+ ConversionService conversionService = this .dataAccessStrategy .getConverter ().getConversionService ();
445
+ Object currentVersionValue = propertyAccessor .getProperty (versionProperty );
446
+ long newVersionValue = 1L ;
447
+ if (currentVersionValue != null ) {
448
+ newVersionValue = conversionService .convert (currentVersionValue , Long .class ) + 1 ;
449
+ }
450
+ Class <?> versionPropertyType = versionProperty .getType ();
451
+ propertyAccessor .setProperty (versionProperty , conversionService .convert (newVersionValue , versionPropertyType ));
452
+ }
453
+
454
+ private <T > Criteria createMatchingVersionCriteria (T entity , RelationalPersistentEntity <T > persistentEntity ) {
455
+ PersistentPropertyAccessor <?> propertyAccessor = persistentEntity .getPropertyAccessor (entity );
456
+ RelationalPersistentProperty versionProperty = persistentEntity .getVersionProperty ();
457
+
458
+ Object version = propertyAccessor .getProperty (versionProperty );
459
+ Criteria .CriteriaStep versionColumn = Criteria .where (dataAccessStrategy .toSql (versionProperty .getColumnName ()));
460
+ if (version == null ) {
461
+ return versionColumn .isNull ();
462
+ } else {
463
+ return versionColumn .is (version );
464
+ }
465
+ }
466
+
409
467
/*
410
468
* (non-Javadoc)
411
469
* @see org.springframework.data.r2dbc.core.R2dbcEntityOperations#delete(java.lang.Object)
0 commit comments