Results 1 to 3 of 3

Thread: [neo4j] Why is graph ID recommended way to implement equals/hashCode?

  1. #1

    Default [neo4j] Why is graph ID recommended way to implement equals/hashCode?

    Hi,

    I have 2 questions:

    1. Why is graph ID recommended way to implement equals/hashCode in SDN? Problem of db identity vs object identity has been long known now, mostly from SQL world, and one article tackling with that is:
    http://onjava.com/lpt/a/6718
    , and solution is to use natural key (any kind of stable fields, or some user-generated ID that is set always during domain object instance creation).

    Database ID is no good for equals/hashCode because it is assigned to object only when it is saved, and until then, 2 different objects seem as equal although they are not. This is especially inconvenient when working with hash collections (such as HashSet). In unit tests we don't even save domain objects ever, because we're working without persistence then.

    Is there any internal requirement in SDN that won't work if we leave out graph ID from equals/hashCode? I can see the problem with SDN's managed Set impl. Unlike Hibernate, which doesn't populate the Set with persisted elements until some method on it has been called (lazy initialization), SDN with simple mapping performs other type of lazy initialization, and that is to populate non-initialized Set with empty elements that have only graph ID populated, which is a major blocker for non-graphID-based equals/hashCode because different domain objects seem equal because they all have natural key with null value, and also fetching the collection changes equals/hashCode while already being present in the Set, which brings all kind of unpredictable behavior. If non-initialized Set would not have any elements populated, same as Hibernate does, then this problem would go away, and proper equals/hashCode with only natural key used could be implemented. One could only argue that we would loose the ability to see graph IDs of collection elements without fetching them completely, but I consider this minor drawback.

    2. Since I never tried advanced mapping, and I've read that neo4jTemplate.fetch is not needed there because properties are always fetched on-demand, does it mean that natural key based equals/hashCode could work then, because whenever HashSet calls equals/hashCode, it would be able to fetch natural key from db?

    Regards,
    Vjeran
    Last edited by vmarcinko; Jul 11th, 2012 at 02:44 AM.

  2. #2
    Join Date
    May 2012
    Posts
    107

    Default

    Vrejan,

    Good point, The current Implementation is a pragmatic compromise. It is unlikely to change in the near future.

    I know that is not much of an answer, but I can reveal that Neo and Spring Data have some roadmap discussions in the works, the impact of which are not yet known.

    But watch this space!

    Lasse

  3. #3

    Default

    Is there any way that when being supported, @PersistenceConstructor annotation will allow the developer to specify what fields should be used for constructor, thus force SDN to always have entities around with specified fields initialized?

    I'm talking something like:

    Code:
    public class MyEntity {
    @GraphId
    private Long graphId;
    
    private String someNaturalKey;
    
       @PersistenceConstructor
       public MyEntity(Long graphId, String someNaturalyKey) {
          this.graphId = graphId;
          this.someNaturalKey = someNaturalKey;
       }
    ...
    Or is this annotation just supposed to use graph ID field?

    Although I expected your answer that the policy won't change anytime soon, but as it is now, there are probably 2 ways handling equals/hashCode:

    1. Either you use some natural key, and cannot expect that application code will behave correctly in all cases (such as removing element from mapped Set)

    2. Or use graph ID as equality field, but then give up from unit tests, and also take care that all your application service methods that work with fresh objects take care to call neo4jTemplate.save(...) immediately after such object has been instantiated

    I have tough time seeing plenty of serious applications accepting the terms above.

    Don't take my comments offensive, I respect your honest answer, and I am sure that SDN developers did their best when designing this mapping lib (maybe for some reason better couldn't be done, or maybe this is design error in the lib, but then again, we all do them).

    Regards,
    Vjeran
    Last edited by vmarcinko; Jul 14th, 2012 at 01:26 AM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •