terrymanu commented on issue #35077:
URL: 
https://github.com/apache/shardingsphere/issues/35077#issuecomment-3502893596

   Problem Understanding
   
     I understand you're experiencing a validation issue after upgrading from 
ShardingSphere Spring Boot Starter 4.1.1 to ShardingSphere JDBC 5.5.1. Your 
setup supports both partitioned and non-partitioned databases using
     common data objects, and the virtual field partition_date in your data 
object is causing validation failures before your sharding algorithm can 
execute.
   
     Root Cause Analysis
   
     This is a configuration validation enhancement in ShardingSphere 5.5.1, 
not a bug. The core issue is:
   
     1. Virtual Field Mapping: Your getPartitionDate() method creates a virtual 
field that doesn't exist in actual database tables
     2. Pre-execution Validation: ShardingSphere 5.5.1 performs stricter table 
structure validation before executing routing logic
     3. First Node Validation: ShardingSphere uses the first node in 
actualDataNodes for initial table metadata validation
   
     Recommended Solutions
   
     Solution 1: Mark Virtual Field with @Transient (Recommended)
   
     Modify your data object to exclude the virtual field from database mapping:
   
   ```java
     @Data
     @Alias("req_unique")
     @Getter
     @Setter
     public class RequestUniqueDO {
         private String requestId;
         private String orderId;
   
         /**
          * This method is used for partitioning logic and should not be mapped 
to any database column.
          * It's used by the sharding algorithm to determine the correct 
database and table.
          */
         @Transient  // Add this annotation to exclude from database mapping
         public Date getPartitionDate() {
             return Utils.composePartitionDate(this.orderId);
         }
   
         // Override the setter to prevent any database mapping
         public void setPartitionDate(Date partitionDate) {
             // No-op - this is a computed field
         }
     }
   ```
   
     Solution 2: Alternative Using Different Data Objects
   
     Consider using separate data objects for partitioned and non-partitioned 
tables:
   
   ```java
     // For non-partitioned tables
     @Data
     @Alias("req_unique")
     public class RequestUniqueDO {
         private String requestId;
         private String orderId;
     }
   
     // For partitioned tables
     @Data
     @Alias("req_unique")
     public class PartitionedRequestUniqueDO extends RequestUniqueDO {
   
         public Date getPartitionDate() {
             return Utils.composePartitionDate(this.orderId);
         }
     }
   ```
   
     Solution 3: Optimize Configuration Order
   
     If you cannot modify the data objects, adjust your actualDataNodes based 
on your primary use case:
   
   ```yaml
     rules:
       - !SHARDING
         tables:
           req_unique:
             # Order nodes based on your primary query pattern
             actualDataNodes: 
db$->{0..1}.req_unique_$->{0..2},dbp$->{0..1}.req_unique_$->{0..1}
             databaseStrategy:
               hint:
                 shardingAlgorithmName: db_complex_sharding_algorithm
   ```
   
     Additional Recommendations
   
     Improve Your Sharding Algorithm
   
     Enhance your DBComplexShardingAlgorithm to handle validation more 
gracefully:
   
   ```java
     public class DBComplexShardingAlgorithm implements 
HintShardingAlgorithm<String> {
   
         @Override
         public Collection<String> doSharding(Collection<String> 
availableTargets,
                                              HintShardingValue<String> 
hintShardingValue) {
   
             List<String> shardingResult = new ArrayList<>();
             Collection<String> values = hintShardingValue.getValues();
             if (values.isEmpty()) {
                 return availableTargets;
             }
   
             String orderId = values.iterator().next();
   
             // Add null check and validation
             if (orderId == null || orderId.isEmpty()) {
                 return availableTargets;
             }
   
             String targetDb;
             if (isPartitionedRequired(orderId)) {
                 targetDb = getPartitionedShard(orderId);
             } else {
                 targetDb = getNonPartitionedShard(orderId);
             }
   
             // Verify target exists in available targets
             if (availableTargets.contains(targetDb)) {
                 shardingResult.add(targetDb);
             }
   
             return shardingResult;
         }
   
         private boolean isPartitionedRequired(String orderId) {
             // Implement your business logic to determine if partitioning is 
needed
             return PARTITIONED_ENABLED && shouldUsePartitioning(orderId);
         }
     }
   ```
   
     Request for Additional Information
   
     If the solutions above don't resolve your issue, please provide:
   
     1. Complete ShardingSphere configuration (including datasource 
configuration)
     2. Database table schemas (DDL statements for both partitioned and 
non-partitioned tables)
     3. Full stack trace of the exception
     4. Example SQL statements that are failing
     5. Spring Boot version and Java version being used
   
     Summary
   
     The issue is caused by enhanced validation in ShardingSphere 5.5.1 that 
checks data object fields against table metadata before routing. The 
recommended solution is to use @Transient annotation to mark virtual fields,
     which is the standard approach in JPA/Spring applications and follows 
ShardingSphere best practices.
   
     This maintains backward compatibility while providing cleaner separation 
between business logic fields and database mapping fields.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to