0
# UpdateChain Fluent Update API
1
2
Fluent, type-safe update operations with method chaining for readable and maintainable database updates. The UpdateChain provides a modern alternative to traditional update methods, combining field setting, condition building, and execution in a single fluent interface.
3
4
## Capabilities
5
6
### UpdateChain Class
7
8
Fluent update builder that combines field setting capabilities with query condition support. Provides type-safe field updates with lambda expressions and comprehensive condition building.
9
10
```java { .api }
11
/**
12
* Fluent update chain for type-safe field updates and condition building
13
* @param <T> Entity type
14
*/
15
public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> implements PropertySetter<UpdateChain<T>> {
16
/**
17
* Create UpdateChain from entity class
18
* Automatically resolves BaseMapper from entity class
19
* @param entityClass entity class type
20
* @return new UpdateChain instance
21
*/
22
public static <T> UpdateChain<T> of(Class<T> entityClass);
23
24
/**
25
* Create UpdateChain from BaseMapper
26
* @param baseMapper mapper instance for the entity
27
* @return new UpdateChain instance
28
*/
29
public static <T> UpdateChain<T> of(BaseMapper<T> baseMapper);
30
31
/**
32
* Create UpdateChain from entity object
33
* Uses object values as update data and resolves mapper automatically
34
* @param entityObject entity instance with update values
35
* @return new UpdateChain instance
36
*/
37
public static <T> UpdateChain<T> of(T entityObject);
38
39
/**
40
* Create UpdateChain from entity object with specific mapper
41
* @param entityObject entity instance with update values
42
* @param baseMapper mapper instance for the entity
43
* @return new UpdateChain instance
44
*/
45
public static <T> UpdateChain<T> of(T entityObject, BaseMapper<T> baseMapper);
46
}
47
```
48
49
### Field Setting Operations
50
51
Set field values for update operations with support for conditional setting and raw SQL expressions.
52
53
```java { .api }
54
// Basic field setting
55
/**
56
* Set field value using property name
57
* @param property field/property name
58
* @param value value to set
59
* @return UpdateChain for method chaining
60
*/
61
public UpdateChain<T> set(String property, Object value);
62
63
/**
64
* Set field value using QueryColumn
65
* @param queryColumn column reference
66
* @param value value to set
67
* @return UpdateChain for method chaining
68
*/
69
public UpdateChain<T> set(QueryColumn queryColumn, Object value);
70
71
/**
72
* Set field value using lambda getter (type-safe)
73
* @param getter lambda expression referencing getter method
74
* @param value value to set
75
* @return UpdateChain for method chaining
76
*/
77
public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value);
78
79
// Conditional field setting
80
/**
81
* Set field value conditionally using property name
82
* @param property field/property name
83
* @param value value to set
84
* @param isEffective whether to include this set operation
85
* @return UpdateChain for method chaining
86
*/
87
public UpdateChain<T> set(String property, Object value, boolean isEffective);
88
89
/**
90
* Set field value conditionally using QueryColumn
91
* @param queryColumn column reference
92
* @param value value to set
93
* @param isEffective whether to include this set operation
94
* @return UpdateChain for method chaining
95
*/
96
public UpdateChain<T> set(QueryColumn queryColumn, Object value, boolean isEffective);
97
98
/**
99
* Set field value conditionally using lambda getter
100
* @param getter lambda expression referencing getter method
101
* @param value value to set
102
* @param isEffective whether to include this set operation
103
* @return UpdateChain for method chaining
104
*/
105
public <L> UpdateChain<T> set(LambdaGetter<L> getter, Object value, boolean isEffective);
106
107
/**
108
* Set field value with BooleanSupplier condition
109
* @param property field/property name
110
* @param value value to set
111
* @param isEffective supplier providing condition evaluation
112
* @return UpdateChain for method chaining
113
*/
114
public UpdateChain<T> set(String property, Object value, BooleanSupplier isEffective);
115
116
/**
117
* Set field value with Predicate condition
118
* @param property field/property name
119
* @param value value to set
120
* @param isEffective predicate to test the value
121
* @return UpdateChain for method chaining
122
*/
123
public <V> UpdateChain<T> set(String property, V value, Predicate<V> isEffective);
124
```
125
126
### Raw SQL Setting Operations
127
128
Set fields using raw SQL expressions for complex update operations, calculations, and database functions.
129
130
```java { .api }
131
// Raw SQL field setting
132
/**
133
* Set field to raw SQL expression using property name
134
* @param property field/property name
135
* @param value raw SQL expression or database function
136
* @return UpdateChain for method chaining
137
*/
138
public UpdateChain<T> setRaw(String property, Object value);
139
140
/**
141
* Set field to raw SQL expression using QueryColumn
142
* @param queryColumn column reference
143
* @param value raw SQL expression or database function
144
* @return UpdateChain for method chaining
145
*/
146
public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value);
147
148
/**
149
* Set field to raw SQL expression using lambda getter
150
* @param getter lambda expression referencing getter method
151
* @param value raw SQL expression or database function
152
* @return UpdateChain for method chaining
153
*/
154
public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value);
155
156
// Conditional raw SQL setting
157
/**
158
* Set field to raw SQL expression conditionally using property name
159
* @param property field/property name
160
* @param value raw SQL expression
161
* @param isEffective whether to include this set operation
162
* @return UpdateChain for method chaining
163
*/
164
public UpdateChain<T> setRaw(String property, Object value, boolean isEffective);
165
166
/**
167
* Set field to raw SQL expression conditionally using QueryColumn
168
* @param queryColumn column reference
169
* @param value raw SQL expression
170
* @param isEffective whether to include this set operation
171
* @return UpdateChain for method chaining
172
*/
173
public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value, boolean isEffective);
174
175
/**
176
* Set field to raw SQL expression conditionally using lambda getter
177
* @param getter lambda expression referencing getter method
178
* @param value raw SQL expression
179
* @param isEffective whether to include this set operation
180
* @return UpdateChain for method chaining
181
*/
182
public <L> UpdateChain<T> setRaw(LambdaGetter<L> getter, Object value, boolean isEffective);
183
184
/**
185
* Set field to raw SQL with BooleanSupplier condition
186
* @param property field/property name
187
* @param value raw SQL expression
188
* @param isEffective supplier providing condition evaluation
189
* @return UpdateChain for method chaining
190
*/
191
public UpdateChain<T> setRaw(String property, Object value, BooleanSupplier isEffective);
192
193
/**
194
* Set field to raw SQL with Predicate condition
195
* @param property field/property name
196
* @param value raw SQL expression
197
* @param isEffective predicate to test the value
198
* @return UpdateChain for method chaining
199
*/
200
public <V> UpdateChain<T> setRaw(String property, V value, Predicate<V> isEffective);
201
```
202
203
### Condition Building Operations
204
205
Build WHERE conditions using the same powerful condition system as QueryWrapper with full support for complex logical expressions.
206
207
```java { .api }
208
// WHERE conditions
209
/**
210
* Add WHERE condition using QueryCondition
211
* @param queryCondition condition to add
212
* @return UpdateChain for method chaining
213
*/
214
public UpdateChain<T> where(QueryCondition queryCondition);
215
216
/**
217
* Add WHERE condition using raw SQL
218
* @param sql raw SQL condition
219
* @return UpdateChain for method chaining
220
*/
221
public UpdateChain<T> where(String sql);
222
223
/**
224
* Add WHERE condition using parameterized SQL
225
* @param sql SQL with parameter placeholders
226
* @param params parameter values
227
* @return UpdateChain for method chaining
228
*/
229
public UpdateChain<T> where(String sql, Object... params);
230
231
/**
232
* Add WHERE conditions from Map (key=value)
233
* @param whereConditions map of field names to values
234
* @return UpdateChain for method chaining
235
*/
236
public UpdateChain<T> where(Map<String, Object> whereConditions);
237
238
/**
239
* Add WHERE condition using Consumer for complex logic
240
* @param consumer consumer that configures nested conditions
241
* @return UpdateChain for method chaining
242
*/
243
public UpdateChain<T> where(Consumer<QueryWrapper> consumer);
244
245
// AND conditions
246
/**
247
* Add AND condition using QueryCondition
248
* @param queryCondition condition to add with AND logic
249
* @return UpdateChain for method chaining
250
*/
251
public UpdateChain<T> and(QueryCondition queryCondition);
252
253
/**
254
* Add AND condition using raw SQL
255
* @param sql raw SQL condition
256
* @return UpdateChain for method chaining
257
*/
258
public UpdateChain<T> and(String sql);
259
260
/**
261
* Add AND condition using parameterized SQL
262
* @param sql SQL with parameter placeholders
263
* @param params parameter values
264
* @return UpdateChain for method chaining
265
*/
266
public UpdateChain<T> and(String sql, Object... params);
267
268
/**
269
* Add AND conditions from Map
270
* @param whereConditions map of field names to values
271
* @return UpdateChain for method chaining
272
*/
273
public UpdateChain<T> and(Map<String, Object> whereConditions);
274
275
/**
276
* Add AND condition using Consumer for nested logic
277
* @param consumer consumer that configures nested conditions
278
* @return UpdateChain for method chaining
279
*/
280
public UpdateChain<T> and(Consumer<QueryWrapper> consumer);
281
282
// OR conditions
283
/**
284
* Add OR condition using QueryCondition
285
* @param queryCondition condition to add with OR logic
286
* @return UpdateChain for method chaining
287
*/
288
public UpdateChain<T> or(QueryCondition queryCondition);
289
290
/**
291
* Add OR condition using raw SQL
292
* @param sql raw SQL condition
293
* @return UpdateChain for method chaining
294
*/
295
public UpdateChain<T> or(String sql);
296
297
/**
298
* Add OR condition using parameterized SQL
299
* @param sql SQL with parameter placeholders
300
* @param params parameter values
301
* @return UpdateChain for method chaining
302
*/
303
public UpdateChain<T> or(String sql, Object... params);
304
305
/**
306
* Add OR conditions from Map
307
* @param whereConditions map of field names to values
308
* @return UpdateChain for method chaining
309
*/
310
public UpdateChain<T> or(Map<String, Object> whereConditions);
311
312
/**
313
* Add OR condition using Consumer for nested logic
314
* @param consumer consumer that configures nested conditions
315
* @return UpdateChain for method chaining
316
*/
317
public UpdateChain<T> or(Consumer<QueryWrapper> consumer);
318
```
319
320
### Execution Operations
321
322
Execute the constructed update or delete operations and return results.
323
324
```java { .api }
325
/**
326
* Execute update operation with configured field changes and conditions
327
* @return true if update affected at least one row, false otherwise
328
*/
329
public boolean update();
330
331
/**
332
* Execute delete operation using configured conditions
333
* @return true if delete affected at least one row, false otherwise
334
*/
335
public boolean remove();
336
337
/**
338
* Generate SQL string for debugging and logging purposes
339
* Includes parameter substitution for complete SQL visualization
340
* @return complete SQL string with parameters substituted
341
*/
342
public String toSQL();
343
```
344
345
## Usage Examples
346
347
### Basic Field Updates
348
349
```java
350
// Simple field updates using different approaches
351
UpdateChain.of(User.class)
352
.set("name", "John Doe")
353
.set("email", "john@example.com")
354
.where("id = ?", 1)
355
.update();
356
357
// Type-safe updates with lambda expressions
358
UpdateChain.of(User.class)
359
.set(User::getName, "Jane Smith")
360
.set(User::getEmail, "jane@example.com")
361
.where(USER.ID.eq(1))
362
.update();
363
364
// Using QueryColumn references
365
UpdateChain.of(User.class)
366
.set(USER.NAME, "Bob Wilson")
367
.set(USER.EMAIL, "bob@example.com")
368
.where(USER.ID.eq(1))
369
.update();
370
```
371
372
### Conditional Field Setting
373
374
```java
375
String newEmail = getNewEmail();
376
boolean updateStatus = shouldUpdateStatus();
377
378
UpdateChain.of(User.class)
379
.set("name", "Updated Name")
380
.set("email", newEmail, StringUtil.isNotBlank(newEmail)) // Only set if not blank
381
.set("status", "ACTIVE", updateStatus) // Only set if condition is true
382
.set("lastModified", LocalDateTime.now(), () -> shouldUpdateTimestamp()) // BooleanSupplier
383
.where(USER.ID.eq(userId))
384
.update();
385
386
// Using Predicate for value validation
387
UpdateChain.of(Product.class)
388
.set("price", newPrice, price -> price > 0) // Only set if price is positive
389
.set("category", newCategory, Objects::nonNull) // Only set if not null
390
.where(PRODUCT.ID.eq(productId))
391
.update();
392
```
393
394
### Raw SQL Expressions
395
396
```java
397
// Using database functions and calculations
398
UpdateChain.of(Account.class)
399
.setRaw("balance", "balance + ?", 100.0) // Add to existing balance
400
.setRaw("lastUpdated", "NOW()") // Use database function
401
.setRaw("version", "version + 1") // Increment version
402
.where(ACCOUNT.ID.eq(accountId))
403
.update();
404
405
// Complex calculations
406
UpdateChain.of(Order.class)
407
.setRaw("totalAmount", "quantity * unitPrice * (1 - discount)")
408
.setRaw("tax", "totalAmount * 0.08")
409
.where(ORDER.ID.eq(orderId))
410
.update();
411
412
// Conditional raw SQL
413
boolean applyDiscount = checkDiscountEligibility();
414
UpdateChain.of(Product.class)
415
.set("name", newName)
416
.setRaw("price", "price * 0.9", applyDiscount) // Apply 10% discount conditionally
417
.where(PRODUCT.CATEGORY.eq("ELECTRONICS"))
418
.update();
419
```
420
421
### Complex Conditions
422
423
```java
424
// Multiple AND conditions
425
UpdateChain.of(User.class)
426
.set("status", "INACTIVE")
427
.set("lastLogin", null)
428
.where(USER.LAST_LOGIN.lt(LocalDateTime.now().minusMonths(6)))
429
.and(USER.STATUS.eq("ACTIVE"))
430
.and(USER.EMAIL_VERIFIED.eq(false))
431
.update();
432
433
// OR conditions with nested logic
434
UpdateChain.of(Product.class)
435
.set("onSale", true)
436
.set("salePrice", "price * 0.8")
437
.where(PRODUCT.CATEGORY.eq("CLOTHING"))
438
.or(wrapper -> wrapper
439
.and(PRODUCT.INVENTORY.gt(100))
440
.and(PRODUCT.CREATED_AT.lt(LocalDate.now().minusMonths(3)))
441
)
442
.update();
443
444
// Map-based conditions
445
Map<String, Object> conditions = new HashMap<>();
446
conditions.put("status", "PENDING");
447
conditions.put("priority", "HIGH");
448
449
UpdateChain.of(Task.class)
450
.set("assignee", newAssignee)
451
.set("updatedAt", LocalDateTime.now())
452
.where(conditions)
453
.update();
454
```
455
456
### Batch-Style Updates
457
458
```java
459
// Update multiple fields based on entity state
460
User user = getUserById(userId);
461
UpdateChain.of(User.class)
462
.set(User::getName, user.getName())
463
.set(User::getEmail, user.getEmail())
464
.set(User::getPhone, user.getPhone())
465
.set(User::getUpdatedAt, LocalDateTime.now())
466
.where(USER.ID.eq(userId))
467
.update();
468
469
// Update with entity object as source
470
User updateData = new User();
471
updateData.setName("Updated Name");
472
updateData.setEmail("updated@example.com");
473
474
UpdateChain.of(updateData) // Use entity as update source
475
.where(USER.ID.eq(userId))
476
.update();
477
```
478
479
### Delete Operations
480
481
```java
482
// Simple delete with conditions
483
UpdateChain.of(User.class)
484
.where(USER.STATUS.eq("DELETED"))
485
.and(USER.LAST_LOGIN.lt(LocalDateTime.now().minusYears(1)))
486
.remove();
487
488
// Conditional delete
489
boolean shouldCleanup = isCleanupScheduled();
490
UpdateChain.of(LogEntry.class)
491
.where(LOG_ENTRY.CREATED_AT.lt(LocalDate.now().minusDays(30)), shouldCleanup)
492
.remove();
493
494
// Delete with complex conditions
495
UpdateChain.of(Session.class)
496
.where(wrapper -> wrapper
497
.and(SESSION.EXPIRED_AT.lt(LocalDateTime.now()))
498
.or(SESSION.LAST_ACTIVITY.lt(LocalDateTime.now().minusHours(24)))
499
)
500
.remove();
501
```
502
503
### SQL Generation and Debugging
504
505
```java
506
// Generate SQL for debugging
507
String sql = UpdateChain.of(User.class)
508
.set("name", "Debug User")
509
.set("status", "ACTIVE")
510
.where(USER.ID.eq(123))
511
.toSQL();
512
513
System.out.println("Generated SQL: " + sql);
514
// Output: UPDATE user SET name = 'Debug User', status = 'ACTIVE' WHERE id = 123
515
516
// Complex update SQL generation
517
String complexSql = UpdateChain.of(Order.class)
518
.setRaw("totalAmount", "quantity * unitPrice")
519
.set("status", "CALCULATED")
520
.where(ORDER.STATUS.eq("PENDING"))
521
.and(ORDER.CREATED_AT.between(startDate, endDate))
522
.toSQL();
523
```
524
525
## Types
526
527
### Supporting Classes and Interfaces
528
529
```java { .api }
530
/**
531
* Interface for setting entity properties with fluent API
532
* @param <R> Return type for method chaining
533
*/
534
public interface PropertySetter<R> {
535
// Field setting methods with various parameter types
536
R set(String property, Object value);
537
R set(QueryColumn property, Object value);
538
<T> R set(LambdaGetter<T> property, Object value);
539
540
// Conditional field setting methods
541
R set(String property, Object value, boolean isEffective);
542
R set(String property, Object value, BooleanSupplier isEffective);
543
<V> R set(String property, V value, Predicate<V> isEffective);
544
545
// Raw SQL field setting methods
546
R setRaw(String property, Object value);
547
R setRaw(QueryColumn property, Object value);
548
<T> R setRaw(LambdaGetter<T> property, Object value);
549
550
// Conditional raw SQL setting methods
551
R setRaw(String property, Object value, boolean isEffective);
552
R setRaw(String property, Object value, BooleanSupplier isEffective);
553
<V> R setRaw(String property, V value, Predicate<V> isEffective);
554
}
555
556
/**
557
* Update wrapper interface for entity modification tracking
558
* @param <T> Entity type
559
*/
560
public interface UpdateWrapper<T> extends PropertySetter<UpdateWrapper<T>>, Serializable {
561
/**
562
* Get map of field modifications
563
* @return map containing field names and their update values
564
*/
565
Map<String, Object> getUpdates();
566
567
/**
568
* Create UpdateWrapper from entity object
569
* @param entity entity instance
570
* @return UpdateWrapper wrapping the entity
571
*/
572
static <T> UpdateWrapper<T> of(T entity);
573
574
/**
575
* Create UpdateWrapper from entity class
576
* @param tClass entity class
577
* @return UpdateWrapper for the entity type
578
*/
579
static <T> UpdateWrapper<T> of(Class<T> tClass);
580
581
/**
582
* Convert back to entity object
583
* @return entity instance with modifications
584
*/
585
T toEntity();
586
}
587
588
/**
589
* Query wrapper adapter providing condition building capabilities
590
* @param <R> Return type for method chaining
591
*/
592
public class QueryWrapperAdapter<R extends QueryWrapperAdapter<R>> extends QueryWrapper {
593
// Inherits all condition building methods from QueryWrapper
594
// Returns parameterized type R for proper method chaining
595
}
596
```
597
598
## Integration Patterns
599
600
### With BaseMapper Operations
601
602
UpdateChain integrates seamlessly with existing BaseMapper operations and can be mixed with traditional CRUD methods:
603
604
```java
605
@Service
606
public class UserService {
607
@Autowired
608
private UserMapper userMapper;
609
610
public void updateUserStatus(Long userId, String newStatus) {
611
// Traditional approach
612
User user = userMapper.selectOneById(userId);
613
user.setStatus(newStatus);
614
user.setUpdatedAt(LocalDateTime.now());
615
userMapper.update(user);
616
617
// UpdateChain approach - more readable and explicit
618
UpdateChain.of(User.class)
619
.set(User::getStatus, newStatus)
620
.set(User::getUpdatedAt, LocalDateTime.now())
621
.where(USER.ID.eq(userId))
622
.update();
623
}
624
625
public void bulkUpdatePrices(String category, BigDecimal multiplier) {
626
// Complex update that would be difficult with entity-based updates
627
UpdateChain.of(Product.class)
628
.setRaw("price", "price * ?", multiplier)
629
.setRaw("updatedAt", "NOW()")
630
.set("modifiedBy", getCurrentUser())
631
.where(PRODUCT.CATEGORY.eq(category))
632
.and(PRODUCT.STATUS.eq("ACTIVE"))
633
.update();
634
}
635
}
636
```
637
638
### Comparison with Traditional Updates
639
640
| Approach | UpdateChain | Traditional Entity Update | BaseMapper updateByQuery |
641
|----------|-------------|-------------------------|-------------------------|
642
| **Readability** | High - fluent, self-documenting | Medium - requires entity manipulation | Low - separate wrapper creation |
643
| **Type Safety** | High - lambda expressions | High - entity properties | Medium - QueryWrapper conditions |
644
| **Flexibility** | High - raw SQL, conditionals | Low - entity constraints | High - full query control |
645
| **Performance** | Optimal - direct SQL | Good - entity mapping | Optimal - direct SQL |
646
| **Maintenance** | Easy - method chaining | Easy - familiar pattern | Complex - wrapper management |
647
648
```java
649
// Traditional entity-based update
650
User user = userMapper.selectOneById(userId);
651
user.setName("New Name");
652
user.setStatus("ACTIVE");
653
userMapper.update(user); // Updates ALL fields
654
655
// UpdateChain - selective field updates
656
UpdateChain.of(User.class)
657
.set("name", "New Name")
658
.set("status", "ACTIVE") // Only updates specified fields
659
.where(USER.ID.eq(userId))
660
.update();
661
662
// Traditional BaseMapper with QueryWrapper
663
QueryWrapper queryWrapper = QueryWrapper.create()
664
.where(USER.ID.eq(userId));
665
User updateEntity = new User();
666
updateEntity.setName("New Name");
667
updateEntity.setStatus("ACTIVE");
668
userMapper.updateByQuery(updateEntity, queryWrapper);
669
670
// UpdateChain - combined in single fluent interface
671
UpdateChain.of(User.class)
672
.set("name", "New Name")
673
.set("status", "ACTIVE")
674
.where(USER.ID.eq(userId))
675
.update();
676
```
677
678
The UpdateChain provides a modern, fluent alternative to traditional update patterns while maintaining full compatibility with existing MyBatis-Flex functionality. It excels at selective field updates, conditional modifications, and complex update scenarios that would be cumbersome with entity-based approaches.