spring-data-relational icon indicating copy to clipboard operation
spring-data-relational copied to clipboard

Consider embedded properties in the QBE queries

Open mipo256 opened this issue 5 months ago • 8 comments

Closes #2099 Closes #1986

This PR enhances the RelationalExampleMapper by making it consider embedded properties and specifiers for them.

As it turned out during resolution of #1986, the embedded properties were kind of ignored in QBE.

Current algorithm works more a less the same way, it just traverses the Example recursively from direct properties defined in the root probe, all the way down to the deeply embedded leafs.

Tests are included in the PR.

CC: @mp911de @schauder

mipo256 avatar Jul 26 '25 10:07 mipo256

Signed-off the commits

mipo256 avatar Aug 05 '25 20:08 mipo256

@mp911de Just to make sure that we're on the same page. The current version of the algorithm accounts for the deeply nested embedded objects, like:

@Table
class Root {

    @Id
    private Long id;

    private String name;

    @Embedded.Nullable
    private EmbbedLevelOne levelone;
    
    public static class EmbeddedLevelOne { 
      
         private String type;
    
         @Embedded.Nullable
         private EmbeddedLevelTwo levelTwo;
    }
}

The problem is that if we unroll the recursion into the for-loop, then the code may get a bit messy, since this is not a tail-recursive function we're dealing with. I've tinkered with it, and the only sensible approach I found is to flatten-out all the properties of all the embedded objects (included deeply embedded) on demand, and store them in some kind of Queue that we can iterate through and then just perform the checking.

I'm unsure that this is the best solution. From my personal, empirical data, I may humbly conclude that objects. Therefore the call stack will probably not be large at all. But again, this is merely my observation.

Now, having said that, I can push the for-loop like approach with Queue and we'll have a look. WDYT, @mp911de, @schauder ?

mipo256 avatar Aug 16 '25 11:08 mipo256

The problem is that if we unroll the recursion into the for-loop, then the code may get a bit messy, since this is not a tail-recursive function we're dealing with.

I think you are beyond what @mp911de asked for. His ask was just replacing the

persistentEntity.doWithProperties((PropertyHandler<RelationalPersistentProperty>) property -> {
   // ...
}

With a for loop:


for (RelationalPersisntentProperty property : persistentEntity) {
    // ....
} 

Not an unrolling of the recursion.

The doWithProperties creates one extra frame on the call stack.

schauder avatar Aug 27 '25 12:08 schauder

@mipo256 can you change it to the suggested for loop?

dschulten avatar Oct 12 '25 16:10 dschulten

Sure @dschulten , I have already prepared necessary changes that address the review comments. I'll ping Mark and Jens once they are ready :)

mipo256 avatar Oct 12 '25 16:10 mipo256

Hey @mp911de, @schauder. I think, the PR is ready for the second round of review

mipo256 avatar Oct 12 '25 19:10 mipo256

@mp911de @schauder trying to nudge politely ;-)

dschulten avatar Nov 15 '25 17:11 dschulten

Now that our GA release is done, we can finally continue over here.

mp911de avatar Nov 17 '25 10:11 mp911de