1
votes

I am trying to implement multi tenancy in Neo4j using OGM. My favourite solution is using labels to label entities with tenants ID. Unfortunately I can not get labels to work in Scala. First, I created my entities like this:

trait Entity {
  @GraphId
  @Property
  var graphId: java.lang.Long = _
}

@NodeEntity
class Tenant extends Entity {

   @Property
   var name: String = _

}

@NodeEntity
class Project extends Entity {

   @Property
   var name: String = _

   @Relationship(`type` = "TENANT", direction = Relationship.OUTGOING)
   var tenant: Tenant = _

   @Labels
   val labels: java.util.Collection[String] = new java.util.ArrayList[String]()

   def this(name: String, tenant: Tenant) {
    this()
    this.labels.add(tanant.uuid.toString)

   }

   def hasLabel(label: String): Boolean = {
     this.labels.contains(label)
   }

}

My repositories just have a simple save method

abstract class Repository[Model <: Entity] {

  def save(entity: Model): Model = {
    val session = getSession()
    session.save(entity)

    entity
  }

}

I created a simple test with an embedded Neo4j database, but the last assertion fails with false (what means that the added label is not persisted).

class ProjectSuite extends BaseSuite with Neo4jOgmTestSuite {

  "Project Model" should {

    "save properly with Tenant label" in {
      val tenant = new Tenant("TestTenant")
      TanantRepository.save(tenant)

      val project = new Project("TestProject", tenant)
      ProjectRepository.save(project)

      assert(project.hasLabel(tenant.uuid.toString))

      val loadedProject = ProjectRepository.findById(project.uuid)
      assert(loadedProject isDefined)
      assert(loadedProject.get.hasLabel(tenant.uuid.toString))
    }

  }

}

Any idea what I am missing here?

1
Side note: been there, done that, went another way. Using tenant ids as labels means you have to generate specific Cypher queries for each tenant, since you can't use a placeholder for a label (as they're used to compute the execution plan). So it gets kind of ugly, and you quickly fill the query cache (where they are parsed / pre-compiled / the execution plan might be computed) as there's a version of each query for each tenant. - Frank Pavageau
Code looks OK, though I might've missed something since I code in Java and Kotlin more than Scala. (I should change that ;) ). Are you able to send a failing sample and I'll debug it for you? I implemented the labels feature in the OGM - [email protected] - Jasper Blues
@Frank Any other options besides these two (what are you using?): graphaware.com/neo4j/2015/01/16/… - Alebon
@jasper-blues Yes, can do this. I will create a new github repo with sample code. I will send you a message when it's ready. - Alebon
@Alebon We simply kept the relationship between the entity node and the Tenant node. The queries always start by checking that the "main" node belongs to the tenant. - Frank Pavageau

1 Answers

1
votes

This issue was a bug in that any class without a get/set method backing the labels field was not supported. It has been fixed, and is available in 2.1.0-SNAPSHOT.