5

I tried the example mentioned in Luanne's article The essence of Spring Data Neo4j 4 in Scala. The code can be found in the neo4j-ogm-scala repository.

package neo4j.ogm.scala.domain

import org.neo4j.ogm.annotation.GraphId;
import scala.beans.BeanProperty
import org.neo4j.ogm.annotation.NodeEntity
import org.neo4j.ogm.annotation.Relationship
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;

abstract class Entity {
  @GraphId
  @BeanProperty
  var id: Long = _

  override def equals(o: Any): Boolean = o match {
    case other: Entity => other.id.equals(this.id)
    case _ => false
  }

  override def hashCode: Int = id.hashCode()
}

@NodeEntity
class Category extends Entity {
  var name: String = _

  def this(name: String) {
    this()
    this.name = name
  }
}

@NodeEntity
class Ingredient extends Entity {
  var name: String = _

  @Relationship(`type` = "HAS_CATEGORY", direction = "OUTGOING")
  var category: Category = _

  @Relationship(`type` = "PAIRS_WITH", direction = "UNDIRECTED")
  var pairings: Set[Pairing] = Set()

  def addPairing(pairing: Pairing): Unit = {
    pairing.first.pairings +(pairing)
    pairing.second.pairings +(pairing)
  }

  def this(name: String, category: Category) {
    this()
    this.name = name
    this.category = category
  }
}

@RelationshipEntity(`type` = "PAIRS_WITH")
class Pairing extends Entity {
  @StartNode
  var first: Ingredient = _

  @EndNode
  var second: Ingredient = _

  def this(first: Ingredient, second: Ingredient) {
    this()
    this.first = first
    this.second = second
  }
}

object Neo4jSessionFactory {
  val sessionFactory = new SessionFactory("neo4j.ogm.scala.domain")

  def getNeo4jSession(): Session = {
    System.setProperty("username", "neo4j")
    System.setProperty("password", "neo4j")
    sessionFactory.openSession("http://localhost:7474")
  }
}

object Main extends App {
  val spices = new Category("Spices")
  val turmeric = new Ingredient("Turmeric", spices)
  val cumin = new Ingredient("Cumin", spices)

  val pairing = new Pairing(turmeric, cumin)
  cumin.addPairing(pairing)

  val session = Neo4jSessionFactory.getNeo4jSession()
  val tx: Transaction = session.beginTransaction()

  try {
    session.save(spices)
    session.save(turmeric)
    session.save(cumin)
    session.save(pairing)
    tx.commit()
  } catch {
    case e: Exception => // tx.rollback()
  } finally {
//    tx.commit()
  }
}

The problem is that nothing gets saved to Neo4j. Can you please point out the problem in my code?

Thanks,

Manoj.

mmwaikar
  • 655
  • 4
  • 14

2 Answers2

2

Scala’s Long is an instance of a Value class. Value classes were explicitly introduced to avoid allocating runtime objects. At the JVM level therefore Scala's Long is equivalent to Java’s primitive long which is why it has the primitive type signature J. It cannot be therefore be null, and should not be used as a graphId. Although Scala mostly will do auto-boxing between its own Long and Java’s Long class, this doesn’t apply to declarations, only to operations on those objects.

Vince
  • 2,181
  • 13
  • 16
  • Thanks Luanne and Vince. I tried changing Scala's Long to java.lang.Long but it didn't help. I still can't save anything in the DB. – mmwaikar Aug 14 '15 at 11:37
  • That's weird because I used your code with java.lang.Long and the graph was persisted – Luanne Aug 18 '15 at 07:20
  • Thanks for the update Luanne. I've noticed one peculiar thing - if my domain classes derive from Entity, then I am unable to save data in Neo4j, but if I include the id property with the @GraphId annotation directly in those classes, then I am able to save data. – mmwaikar Aug 31 '15 at 07:00
0

The @GraphId isn't being picked up on your entities. I have zero knowledge of Scala but it looks like the scala long isn't liked much by the OGM; var id: java.lang.Long = _ works fine.

Luanne
  • 19,145
  • 1
  • 39
  • 51