Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Making Things Better: Migrating Spring Data Neo4j 3.x to 4.0 - Sessions and Repositories

DZone's Guide to

Making Things Better: Migrating Spring Data Neo4j 3.x to 4.0 - Sessions and Repositories

Migrating to Spring Data Neo4j's latest version, 4.0, is easy but requires a little effort. This series takes us through the process with an actual example, highlighting several differences and improvements.

· Database Zone
Free Resource

Read why times series is the fastest growing database category.

When we last left our super-series, we introduced Spring Data Neo4j (SDN) 4.0, including some basics required in order to migrate and setup an SDN 4.0 project.  In typical Mad Grapher style (i.e. my style, however typical—or stylish—it may or may not be), we are walking through this migration by way of my favorite computer store replacement, Von Neumann's (you can check out my original post from eons ago here).

In this installment, we are going to introduce a concept new to Spring Data Neo4j: Sessions.

No, not THAT type!

No, not that type!

While I strongly recommend digging into SDN's documentation concerning sessions, we are going to keep things fairly simple for the purposes of this article.

Introduction to the Session

(Or, as I catch myself calling it sometimes, "the sesh".  I really need to get out more.)

At the very core of SDN 4.0 lies Neo4j's object-graph model (OGM) implementation.  This OGM relies heavily upon these "sessions".  In fact, all SDN repository implementations and even the Neo4jTemplate class itself are driven by sessions.

Crucial to understanding a session is understanding its lifecycle.  A session tracks any changes made to both nodes and relationships, which makes persisting back to the graph particularly efficient since only those entities that have changed are saved!  That is awesome news, especially if you happen to be working with large graphs.

And, to sweeten the deal, a session will never return cached objects; in other words, on load, a session will always hit the database—stale data is a non-issue!

Let's quickly revisit the Java-based configuration for sessions as well as the session factory that is used to produce sessions:

    @Bean
    public SessionFactory getSessionFactory() {        
        return new SessionFactory("com.bhsconsultants.vonneumanns.entities");
    }

    @Bean
    @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Session getSession() throws Exception {
        return super.getSession();
    }

Nothing super complicated here, but let's have a closer look at the lifecycle of a session, and also of a session factory, which can also have a scope.

The Session Lifecycle

The lifecycle of a session can be configured by the developer: One can surmise that a longer-scoped session will incur additional memory overhead, but will result in more efficient query executions given the local cache of entities.  However, unless these entities are reloaded periodically, one might miss changes made by other users and end up working with outdated objects.

If one decides to use shorter-scoped sessions, memory overhead is all but eliminated although queries might not be as efficient as they might otherwise be.  This is especially true for save operations, as the session might not be aware of objects that were originally loaded and will therefore update all objects.

So, there are tradeoffs.

A best practice is to set the scope of a session to correspond to what can be considered a "unit of work" in your application. 

From the SDN 4.0 manual:

"What this means depends on the usage scenario, but in a typical web-based Spring application we recommend using a request-scoped or HTTP-session-scoped Session. Either way, if you make sure you load fresh data at the beginning of each unit of work then data integrity shouldn’t be a problem."

Not to be left out, the session factory can also be scoped.  The session factory sets up any object-graph mapping metadata.  Although it is recommended to keep the session factory scope to be that of the application, the scope can be set narrower, if so desired, although the benefits of doing so are likely to be negligible.

So, What Can I Do with a Session?

Since Session drives Neo4jTemplate, and you are undoubtedly familiar with the Neo4jTemplate of yore, you can imagine that a session is what enables the majority of interactions with the graph itself.

That said, there are substantial differences between the old and new Neo4jTemplate classes.

In previous versions of SDN, the Neo4jTemplate class allowed us to interact directly with the nodes and relationships of a graph, permitting us to create relationships, find specific nodes via some index, etc.

These conveniences have been moved out, taking a more Cypher-centric approach; that is, the operations we typically perform with nodes and relationships now primarily happen via working with our POJO entities and saving them, or through Cypher queries issued via the Neo4jTemplate class.  (You can still load several nodes based on properties/entity types, though.)

Let's look at a quick example.

In my original Von Neumann's Store, we had the following method:

public Purchase makePurchase(Neo4jOperations template, Stock item, int quantity)
{
  return template.createRelationshipBetween(this, item, Purchase.class, "PURCHASED", false);
}

Since createRelationshipBetween(...) has been removed, the same method is now implemented like so:

public Purchase makePurchase(Neo4jOperations template, Stock item, int quantity)
{
  final Purchase purchase = new Purchase();
  purchase.setCustomer(this);
  purchase.setItem(item);

  template.save(purchase);

  return purchase;
}

The only real difference is that we have to work with the POJOs directly and then call the template's save(...) method in order to create the relationship.

Not too bad of a change.

We will cover working with SDN POJOs/entities in a later post.  (Hey, we have to save some fun stuff for later!)

Check out the documentation for the Neo4jTemplate class here.


Repo(sitories) Man

Image title

C'mon, you totally saw that coming.

(Courtesy of: rogerebert.com)


Seeing as we are discussing sessions and working with the graph, we might as well discuss SDN's implementation of Spring Data Commons' repository interfaces.

In previous versions of Spring Data Neo4j, we relied a lot on GraphRepository<T> and RelationshipOperationsRepository<T> when creating our own repositories.  Big changes have been made with respect to repositories, and you will find that the only repository you will be using is an updated GraphRepository interface by the same name.  The other interfaces you may have used have been removed and/or rolled in to this single interface.

Also worth noting is that GraphRepository no longer combines IndexRepository and TraversalRepository as both of those interfaces are no longer supported.  

We will revisit SDN's support for indexing and traversals in a later post.

The new GraphRepository still supports all of the CRUD operations you know and love, as well as the same finder and query method definitions you have come to know and love.

Let's have a quick look at one of Von Neumann's Store's repositories, shall we?

public interface GameRepository extends GraphRepository<Game> {
Game findByGameId(String id);

@Query("MATCH (g1:Game {gameId: {0} }), (g2:Game {gameId: {1} }), p = shortestPath( (g1)-[*]-(g2) ) RETURN p")
Iterable<Map<String, Object> > getPath(String game1Id, String game2Id);
}


  • findByGameId, when called, will find any nodes of type/label "Game" with the "gameId" property equal to the string "id" that is passed in.  Derived finder methods FTW!

  • getPath will perform the specified Cypher query, feeding in the necessary parameters at the tokenized locations.  If you will recall, one of the biggest issues I had with the previous version of Von Neumann's Store was the inability to traverse paths containing arbitrary node and relationship types.  While this has not been sorted out (and likely won't, given the static nature of Java--we can always use reflection or some other checking!), the ability to map back to an Iterable containing a Map of <String, Object> pairs gets us just that much closer.

How cool is all that?  ("Do I know what 'rhetorical' means?!")


Conclusion

In this post we have been introduced to SDN 4's paradigm of sessions, along with how it is used and what it means to developers.  

On top of that, we also had a look at how we can perform some basic interactions with the graph via Neo4jTemplate and SDN's repositories.  Both of these concepts make working with a graph rather easy, having streamlined Spring Data Neo4j's previous methods.

I strongly suggest having a look through the updated interface/class definitions for SDN 4 whenever additional clarification is needed.

So, that's it for this post!  As always, if you have any questions/comments/concerns—or even if I've got something wrong—leave comments below and I will do my utmost to address them.

Next time we will get to the topic you have all undoubtedly been waiting for: SDN POJOs and entities!  Hooray!

Image title


See you on the next post, folks!

Learn how to get 20x more performance than Elastic by moving to a Time Series database.

Topics:
neo4j ,spring data neo4j ,graph databases

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}