@EnableSpringDataWebSupport + @PathVariable + depth

I just found out about @EnableSpringDataWebSupport and already love the possibility to simply

@PathVariable("id") Contact contact

but 20 seconds after I refactored a Controller to use this awesome feature I came across the need to load an object to depth 2. Of course I took a leap of faith and tried adding @Depth like

@PathVariable("id") @Depth(2) Contact contact

but that doesn't have any effect.

Is there a way to do this or will this be added?

Cheers, ChrisP

The @Depth annotation is meant to be used on your repository methods or in their method parameter definitions. It has no effect if you put this at the same level as your controller method parameters.

I know and realize that BUT it would be good to have a depth option for the DomainClassConverter that gives me a materialized domain object ... hence my original question :) ... because the default depth of 1 is sometimes not enough

How would that differ from providing the @Depth information on the method or in the method parameters in the repository? Your use-case seems to be to provide a fixed depth. Why should that be at the controller level since it is completely database related?
Maybe I do not see your idea behind this right now :wink:

Here is the section where the usage of it is described in the code example:

Servus Gerrit ;)

The depth is extremely use case specific ... one controller/rest endpoint might need the data with depth 0, the other one with depth 1 and yet another one with depth X ... exactly why we can provide a depth parameter to repo.findById(id, depth) ... isn't it?
So why would I lock the depth on the repository level when this can really only be decided at the exact location of where the data is being requested and used?

Pseudo example:
Before @EnableSpringDataWebSupport

getContact(@PathVariable long id) {
  Contact c = contactRepo.findById(id, 0).get();
getFullContact(@PathVariable long id) {
  Contact c = contactRepo.findById(id, 2).get();  // maybe includes addresses and other related stuff

With @EnableSpringDataWebSupport

getContact(@PathVariable("id") Contact contact) {
  // contact always loaded with depth 1 ... unnecessarily too much for this use-case
getFullContact(@PathVariable("id") Contact contact) {
  // contact always loaded with depth 1 ... not usable here

Seems to me that the whole idea behind repo.findById(id, depth) has been forgotten for @EnableSpringDataWebSupport
Which is why I asked if this will be added in the future in my original post ... I really think this would make sense and considering the fact that we already have an annotation that would fit here (@Depth) that is what I would consider a well-rounded solution ;)

Cheers, Chris

Just realized that there is some major issue with this anyway!
Not sure if I am missing something but this is a huge problem:

I have @EnableSpringDataWebSupport on the WebConfig
and in a RestController:

public DTO patchContact(... @PathVariable("id") Contact contact ...) {

the new data is stored BUT Contact has a "owner" relation to a User and a User has a "sponsor" relation to another user like (c:Contact)-[:OWNER]->(u:User)-[:SPONSOR]->(s:User)
and the above code KILLS (!!) the sponsor relation!!! OMG!

Where this works just fine (without deleting any relations):

public DTO patchContact(... @PathVariable("id") long id ...) {
  Contact contact = contactRepo.findById(id).get();

What am I missing here? Isn't the "WebSupport" simply doing a findById() in the background? Is there a problem with TX handling here.... ???

FYI: Just upgraded to Spring framework 5.2.0.RELEASE and spring-data-neo4j 5.2.0.RELEASE as well as neo4j-ogm-bolt-driver 3.2.2 hoping that maybe this problem has been resolved but this very much UNWANTED behavior still remains :frowning:

This will get a little bit longer now:
It is correct that findById gets triggered with its default depth of 1.
Loading, manipulating and saving an entity should always happen within one transaction because (besides other things) keeping track of the depth the objects were loaded with.
I do not know yet where your @Transactional boundaries are, if there are any.

If you are using the transactional mechanism you should keep in mind that one transaction is technically one SDN/OGM session in the background with its very own cache and track of the depth.
In the first case the retrieval of the Contact happens (most likely) in a different transaction than your data manipulation. When saving the entity OGM does not know how "deep" it was fetched before and wants to store all reachable relationships/nodes. Jumping into the second example it looks about the same.

I just assume for now that, because there are a different loading mechanism in WebSupport and plain loading, one collection is empty and the other is null and this leads to the different behaviour.

I wanted to show some reaction because your finding is really valuable to us. We need some time to dig deeper into this and I will come back with more information. I am not yet 100% sure (anymore) if null or empty makes any difference when the entities should get persisted and it is beyond the loading depth.

Thanks for your answer - I am looking forward to hearing about your findings!
FYI @Transactional is at the Controller level
Cheers, Chris

Hi Gerrit,
any news on this?

I am starting a new project and would like to use this feature to avoid all the repo.findById(id).get(); calls but only if it doesn't destroy my data.

I would simply assume that the @Transactional on the Controller is wrapped around the entire request and makes sure that the data loaded by WebSupport runs in the same TX and OGM session as my method body ... otherwise this entire WebSupport feature is not usable in MOST cases anyway?

Cheers, Chris