AutoIndex feature gone in SDN 6?

Hello @gerrit.meier

I can't find anything in the SDN docs about indexing ... No more @Index and autoIndex(AutoIndexMode.UPDATE)?

Cheers, Chris

Also:
What about repository level events like onPostSave and onPostDelete (from OGM's EventListenerAdapter)?

@gerrit.meier

I had to import OGM and use their labels (@Index) even though I had SDN6 imported. I also had to configure the SessionFactory to enable the autoIndex("update")

Is that really what SDN 6 should be?
We need stuff from the old libs?

I also found out today that (bidirectional) @Relationship mappings don't really work and I wonder if this is by design ... because relationships get deleted!!!

For example:

@Node
class A {
  ....
  @Relationship List<B> bs;
  ...
}

@Node
class B {
  @Relationship A a;
}

If you now load an A entity, add a new B to the list of bs and save A or B, then all the connections to existing Bs get deleted! Digging into this I found that the Bs in the List have a set to null (do not get hydrated with A when A loads)

Haven't tried other (more complex) mappings yet but I guess it will be even worse and connections will get lost (because things only get loaded to depth 1???)

We intentionally did not re-implement this in SDN 6. The feature itself brought a lot of customer confusions (mainly because of the asynchronous nature of the index creation) but also created a lot of maintenance to handle every support database version right.
And in the end it is not a feature from an O[G/R/*]M but something that should be solved on the database side, say DBA or other tooling. For this we created https://github.com/michael-simons/neo4j-migrations or you could use https://github.com/liquibase/liquigraph.

No, please don't ;)

Yes, relationships will get deleted but this should of course not happen if A (and its related entities) were loaded and hydrated. Could you provide an example with a little bit more information about the Node classes (like id type, generated or not..) or even better a failing test scenario.

Also the assumption that we load with depth 1 is wrong because there is no limitation.

Hi @gerrit.meier Thank you for your reply!

1

The @Index is - was - a REALLY awesome feature because the Java classes are effectively a schema for a schemaless DB and what better place to define which fields should get an index than in the schema?
Without this, it is definitely a step backwards and I have to go back abut 4 years and maintain a file of Cypher statements to drop/create indexes when deploying new app versions :cry:

2

Also very important and missing now:

  • something like onPreSave e.g. for giving each entity a UUID (in addition to the @Id @GeneratedValue Long id) or some other calculated values
  • onPostSave, onPostDelete for things like updating an external index

@DomainEvents is great for some certain things but not for this (unless I am completely wrong and missing something ? but I can't see how I would get the info if the entity was created/updated/deleted).
Of course I could publish an applicationEvent EVERYWHERE I save/delete an entity but I think it would be much better (and easy to implement?) if Neo4jTemplate & Repositories published some generic Neo4j events that we can listen for (possibly enabling this feature with a @EnableNeo4jEvents).
No?

3

Importing old libs: Didn't think so, don't want to ;)

4

Regarding the bidirectional relationship: I haven't used those for years because it always caused problems with OGM and now I thought with the new SDN6 I would give it a try again. So here is a compact version of what I want to do:

public abstract class Node {
	@Id @GeneratedValue @Getter private Long id;
	@Version @Getter private Long version;
	@CreatedDate @Getter private LocalDateTime created;
	@LastModifiedDate @Getter  private LocalDateTime modified;
	@Getter private String uuid; // <-- see nescessary onPreSave above!
}

@Node
@Getter
@Setter
public class Page extends Node {
	private String title;
	...
	@Relationship(type = "PAGE", direction = Relationship.Direction.INCOMING) private List<File> files = new ArrayList<>();
}

@Node
@Getter
@Setter
public class File extends Node {
	@Relationship(type = "PAGE") private Page page;
	private String name;
	...
}

// add a new file:
Page page = pageRepo.findById(id).get();
File file = new File();
file.setPage(page);

// option 1:
fileRepo.save(file); // deletes all existing connections between page and other files

// option 2:
page.getFiles().add(file);
pageRepo.save(page); // also deletes all existing connections between page and other files

// here: only the new file is connected to the page anymore

The existing files [loaded when the page is loaded] all have a getPage() of null (!) and by saving the page [either directly or indirectly through saving the new file] deletes the existing relationships.

Regarding onPreSave / onPostSave / onPostDelete:

I am thinking something like this (not sure if this is really the best way to go but you get my point):

@EventListener
public void handleNeo4jEvent(Neo4jEvent event) {
	if (event.getEntity() instanceof MyBaseNode) {
		if (event.getType() == Neo4jEventType.PRE_SAVE) {
			MyBaseNode node = (MyBaseNode) event.getEntity();
			if (StringUtils.isBlank(node.getUuid())) node.setUuid(UUID.randomUUID().toString());
		}
	}
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleNeo4jAfterCommit(Neo4jEvent event) {
	if (event.getEntity() instanceof Page) {
		if (event.getType() == Neo4jEventType.SAVED) {
			// update external index or file system
		} else if (event.getType() == Neo4jEventType.DELETED) {
			// delete entry from index, delete files from FS
		}
	}
}

@gerrit.meier

Actually it would be best to be able to receive events for CREATED, UPDATED and DELETED (not just saved and deleted like my previous post might suggest)

Background: I regularly push info about object C(R)UD events to clients via web-sockets