Use of “@RelationshipProperties” in Spring data Neo4j.

Let’s see there is a request and we have indeed the Transport we wanted. So that’s a very simple example that gives you an idea of Neo4j-OGM concepts. One difference as well is that you also have top-level relationship entities, which is something that does not quite exist in Spring Data Neo4j 6, right? Maybe I should reopen just to contrast it with the project we have.

If we look, for instance, at how we model ConnectionTransport, that’s a node, but we have “@RelationshipProperties”. But that does not make it an entity, right? That’s not a top-level concept, just a way to aggregate some common properties and not target. And you could reuse it in different contexts actually, so that’s quite useful, and a bit more powerful than a top-level relationship, because top-level relationships in Neo4j-OGM, I’m just going to write a fake one, just to show a little. It’s fixed- The types at start and end are fixed, whereas, in Spring Data Neo4j 6, only the target is fixed. So I don’t know. I’m just going to write “SomeRel”. You can have a “@Relationship” entity. So again, that’s Neo4j-OGM annotation. You can give it a type if you want to, that’s if we begin right from the class name. And then you have “@StartNode”.

In that case, I’m just going to do something stupid which would be a “NodeEntity” type, with “start” and “end”. And then you could have extra properties if you want to. Very useful model, of course. And then of course you would have to generate everything else And you would need an “@Id”, I believe. In that case, I’m just going to be lazy and use- Actually, I should have done that right- So something like this plus getters, setters, etc. That’s a bit different. That’s a top-level entity. In Spring Data Neo4j 6, there is no top-level entity, And so you don’t have, contrary to Spring Data Neo4j 5, you don’t have repositories for relationships. That does not exist anymore.

Because of the central concepts, and it’s actually true when you match something with Cypher, you always start from a node. You don’t start with just relationships. You need to specify some patterns of nodes. So Spring Data Neo4j 6 in a way, its philosophy is much closer to Cypher’s philosophy and Cypher’s model, than Spring Data Neo4j 5. Spring Data Neo4j 5 is trying to cover more use cases, more broadly, and so of course, that makes it harder to maintain, and sometimes has some obscure features that are colliding with each other. So for instance, if I take- one thing that I still don’t understand very well, ’cause I have not used it much, but when you want to- Sorry, not in SessionFactory, but- I have a session that I should close at some point, I think.

When you load something, you can also- Let me check. Somewhere over the rainbow. You have paging of course, etc., but that’s not what I want to show. Let me check real quick. Get my notes. “” and “session.load()”, right? “” and “session.load()”. I could say, “Please load these Transports.” It’s going to do something stupid over here. With some depth. Except I don’t define it anymore. Three, two. There was… Let me check real quick.

Is that the second one? And so you need to give a- Let me check. Yeah. Sorry. I am mistaken. “Transport. class” is the type, the ID, which would be whatever. And then we can say, “How much? Based on that start node, how far do you want to go?” ‘Cause, that’s the Load depth. By default, it’s “1”, which means it’s going to fetch the Transport and its tree, and its direct neighbors. It could be -1, so go as deep as needed, So neighbors of neighbors, of neighbors, of neighbors.

You could end up with a very, very big cache of your graph in memory. So you could blow out your memory usage because of this. It’s only useful if you have like, very deep, but not very wide graph structures. And so similarly you have the same- So it’s called the “depth”, “load depth” or “load horizon”, or you can call it whatever you like. So that’s a nice optimization, but in my opinion, it’s only an optimization. You should not use it unless you know what you’re doing. And especially if you start to mix different depths in the same session.

It might be messed up, ’cause you might have retained more objects than the ones that are flushed, and then you could end up with data loss, or unexpected results. It makes things much, much harder to reason about. So if you have a Spring Data file or Neo4j-OGM application, double-check what you’re doing if you’re using custom depths for “load()” or “save()” or both ’cause those are useful for optimization, but only for that. And if you can find an alternative, like a custom query in your repository that does the job well, use that. Don’t use load depths or save depths In my opinion, it’s hard to understand, It’s hard to reason about, it’s hard to maintain, so don’t use it in any way.

It’s gone. It’s completely gone from SDN 6, so you’re not going to have that. Similarly, as I was saying, you could save a specific entity with a specific depth. And that also can be tricky, because you’re not going to save by default, a whole graphic attached to that specific entity, but you could save less, etc. And so yeah. That could lead to unexpected results. So I’m personally not a big fan of it. I’ve not really used Spring Data Neo4j 5 before, so there might be valid use cases, but in my opinion, it looks more like an optimization than a real, like the default go-to thing you want to use.

So if you have some custom depths like that, double-check them, make sure you understand them, make sure there is an alternative to that, ’cause that’s going to make your migration to Spring Data Neo4j 6 much, much harder. If you can use custom queries, go the custom query way. If you can afford to load everything or save everything, do that, because sometimes we optimize without concrete reasons, without any measurements.

If you can avoid this, and if there is no bad impact, just go for it. But, yeah. Try to find an alternative. So in short, you’ve got SessionFactory with a tiny abstraction over the Transport, because Spring Data Neo4j-OGM supports Bolt, HTTP, and embedded, whereas Spring Data Neo4j 6 only supports Bolt. And then you’ve got SessionFactory, like in Hibernate, which then can create sessions. And then you’ve got also your usual operations in there. So that’s just a small detour oriented just to get you to know if you don’t know, Neo4j-OGM. Given I’m talking about migration, if you don’t know Spring Data Neo4j 5/OGM, then it might not be super relevant to you.

Cause if you start on your project, again, start with Spring Data Neo4j 6, unless you’ve got very, very strong reasons to, for instance, use embedded or- And even then, there are ways, again, to you make it work with Spring Data Neo4j 6, or if you need HTTP, but that remains to be- You basically have the- You have to prove that you need it. The default should be “use Spring Data Neo4j 6” unless you can prove that it cannot work in your context. That’s the way I’m going to phrase, I guess. And so let’s talk about migration now. So bye-bye OGM. Bye-bye Neo4j Admin.

Leave a Comment