Skip to content
Browse files

neo4j: fixing a bug one one-to-one relationships

  • Loading branch information...
1 parent 81ecc81 commit ffb4b24ebe42921eb4536d705d9937113007dfa0 @sarmbruster sarmbruster committed Mar 15, 2013
View
31 ...-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jSession.groovy
@@ -107,7 +107,7 @@ class Neo4jSession extends AbstractAttributeStoringSession implements PropertyCh
FlushModeType flushMode = FlushModeType.AUTO;
protected Map<Serializable, Object> objectToKey = new ConcurrentHashMap<Serializable, Object>();
- protected inserts = new ConcurrentLinkedQueue()
+ protected inserts = Collections.synchronizedSet(new HashSet())
protected Map<Class, Persister> persisters = new ConcurrentHashMap<Class, Persister>();
protected dirtyObjects = Collections.synchronizedSet(new HashSet())
protected nonMonitorableObjects = Collections.synchronizedSet(new HashSet())
@@ -152,18 +152,19 @@ class Neo4jSession extends AbstractAttributeStoringSession implements PropertyCh
def value = entityAccess.getProperty(association.name)
switch (association) {
case ToOne:
- if (value && !value.id) {
- persist(value)
- }
-
- if ((value != null) && association.bidirectional) {
- EntityAccess reverseEntityAccess = new EntityAccess(association.associatedEntity, value)
- addObjectToReverseSide(reverseEntityAccess, association, o)
+ if (value!=null) {
+ if (!value.id) {
+ persist(value)
+ }
+ if ((association instanceof ManyToOne) && association.bidirectional) {
+ EntityAccess reverseEntityAccess = new EntityAccess(association.associatedEntity, value)
+ addObjectToReverseSide(reverseEntityAccess, association, o)
+ }
}
break
case ManyToMany:
case OneToMany:
- if (value) {
+ if (value!=null) {
value.findAll { !it.id }.each {
persist(it)
if (association.bidirectional) {
@@ -222,10 +223,12 @@ class Neo4jSession extends AbstractAttributeStoringSession implements PropertyCh
@Override
void flush() {
// do not iterate directly since we might add some entities to objects collection during iteration
- def objects = [] as ConcurrentLinkedQueue
- objects.addAll(nonMonitorableObjects)
- objects.addAll(dirtyObjects)
- objects.addAll(inserts)
+ def startingSet = new HashSet(nonMonitorableObjects.size() + dirtyObjects.size() + inserts.size())
+ startingSet.addAll(nonMonitorableObjects)
+ startingSet.addAll(dirtyObjects)
+ startingSet.addAll(inserts)
+
+ def objects = new ConcurrentLinkedQueue(startingSet)
if (log.infoEnabled) { // TODO: add @Slf4j annotation when groovy 1.8 is used
log.info "pre flush counting: nonMonitorable: ${nonMonitorableObjects.size()}, dirty: ${dirtyObjects.size()}, inserts: ${inserts.size()}, total: ${objects.size()}"
@@ -419,7 +422,7 @@ class Neo4jSession extends AbstractAttributeStoringSession implements PropertyCh
def referencePropertyAccess = new EntityAccess(association.associatedEntity, value)
switch (association) {
case OneToOne:
- referencePropertyAccess.setProperty(association.referencedPropertyName, obj)
+ //referencePropertyAccess.setProperty(association.referencedPropertyName, obj)
//value."${prop.referencedPropertyName}" = obj
break
case ManyToOne:
View
3 grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/JoinCriteriaSpec.groovy
@@ -55,8 +55,7 @@ class AclObjectIdentity {
@Override
String toString() {
- "AclObjectIdentity id $id, aclClass $aclClass.className, " +
- "objectId $objectId, entriesInheriting $entriesInheriting"
+ "AclObjectIdentity id $id, aclClass $aclClass.className, objectId $objectId"
}
}
View
57 grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/ManyToManySpec.groovy
@@ -6,7 +6,7 @@ class ManyToManySpec extends GormDatastoreSpec {
@Override
List getDomainClasses() {
- [Role, User]
+ [Role, User, MBook, MBookworm]
}
/*def setupSpec() {
@@ -162,6 +162,24 @@ class ManyToManySpec extends GormDatastoreSpec {
}
+ def "should two one-to-one relationships be independent"() {
+
+ setup:
+ def randy = new MBookworm(name: 'Randy', favoriteBook: null)
+ randy.save(failOnError: true)
+ def encyclopedia = new MBook(name: 'Encyclopedia Volume 1', checkedOutBy: randy)
+ encyclopedia.save(failOnError: true)
+ session.flush()
+ session.clear()
+
+ when:
+ randy = MBookworm.findByName('Randy')
+
+ then:
+ randy.favoriteBook==null
+
+ }
+
}
@Entity
@@ -218,3 +236,40 @@ class Role {
role(blank: false, unique: true)
}
}
+
+@Entity
+class MBook implements Serializable {
+ Long id
+ Long version
+
+ String name
+ MBookworm checkedOutBy
+
+ static constraints = {
+ name(nullable: false)
+ checkedOutBy(nullable: false)
+ }
+
+ public String toString() {
+ return "Book [name: ${this.name}, checkedOutBy: ${this.checkedOutBy?.name}]"
+ }
+
+}
+
+@Entity
+class MBookworm implements Serializable {
+ Long id
+ Long version
+
+ String name
+ MBook favoriteBook
+
+ static constraints = {
+ name(nullable: false, blank: false)
+ favoriteBook(nullable: true)
+ }
+
+ public String toString() {
+ return "Bookworm: [name: ${this.name}, favoriteBook: ${this.favoriteBook?.name}]"
+ }
+}
View
145 grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/OneToManySpec.groovy
@@ -1,145 +0,0 @@
-package grails.gorm.tests
-
-import spock.lang.Ignore
-
-/**
- * @author graemerocher
- */
-class OneToManySpec extends GormDatastoreSpec {
-
- void "test save and return unidirectional one to many"() {
- given:
- Person p = new Person(firstName: "Fred", lastName: "Flinstone")
- Country c = new Country(name:"Dinoville")
- .addToResidents(p)
- .save(flush:true)
-
- session.clear()
-
- when:
- c = Country.findByName("Dinoville")
-
- then:
- c != null
- c.residents != null
- c.residents.size() == 1
- c.residents.every { it instanceof Person } == true
-
- when:
- c.addToResidents(new Person(firstName:"Barney", lastName:"Rubble"))
- c.save(flush:true)
- session.clear()
- c = Country.findByName("Dinoville")
-
- then:
- c != null
- c.residents != null
- c.residents.size() == 2
- c.residents.every { it instanceof Person } == true
- }
-
- void "test save and return bidirectional one to many"() {
- given:
- Person p = new Person(firstName: "Fred", lastName: "Flinstone")
- p.addToPets(new Pet(name: "Dino", type: new PetType(name: "Dinosaur")))
- p.save(flush:true)
-
- new Person(firstName: "Barney", lastName: "Rubble")
- .addToPets(new Pet(name: "T Rex", type: new PetType(name: "Dinosaur")))
- .addToPets(new Pet(name: "Stego", type: new PetType(name: "Dinosaur")))
- .save(flush:true)
-
- session.clear()
-
- when:
- p = Person.findByFirstName("Fred")
-
- then:
- p != null
- p.pets != null
- p.pets.size() == 1
- def pet = p.pets.iterator().next()
- pet instanceof Pet
- pet.name == 'Dino'
- pet.type != null
- pet.type.name == 'Dinosaur'
-
- when:
- p.addToPets(new Pet(name: "Rex", type: new PetType(name: "Dinosaur")))
- p.save(flush:true)
- session.clear()
- p = Person.findByFirstName("Fred")
-
- then:
- p != null
- p.pets != null
- p.pets.size() == 2
- p.pets.every { it instanceof Pet } == true
- }
-
- void "test update inverse side of bidirectional one to many collection"() {
- given:
- Person p = new Person(firstName: "Fred", lastName: "Flinstone").save()
- new Pet(name: "Dino", type: new PetType(name: "Dinosaur"), owner:p).save()
- Person p2 = new Person(firstName: "Barney", lastName: "Rubble").save()
- new Pet(name: "T Rex", type: new PetType(name: "Dinosaur"), owner:p2).save()
- new Pet(name: "Stego", type: new PetType(name: "Dinosaur"), owner:p2).save(flush:true)
-
- session.clear()
-
- when:
- p = Person.findByFirstName("Fred")
-
- then:
- p != null
- p.pets != null
- p.pets.size() == 1
- def pet = p.pets.iterator().next()
- pet instanceof Pet
- pet.name == 'Dino'
- pet.type != null
- pet.type.name == 'Dinosaur'
- }
-
- void "test update inverse side of bidirectional one to many happens before flushing the session"() {
- given:
- Person person = new Person(firstName: "Fred", lastName: "Flinstone").save()
- Pet dino = new Pet(name: "Dino", type: new PetType(name: "Dinosaur"), owner:person).save()
- Pet trex = new Pet(name: "Trex", type: new PetType(name: "Dinosaur"), owner:person).save()
-
- expect:
- dino.owner == person
- trex.owner == person
- person.pets.size() == 2
-
- when:
- session.flush()
- session.clear()
- person = Person.findByLastName('Flinstone')
-
- then:
- person
- person.pets.size()==2
-
- }
-
- @Ignore // FIXME: broken in neo4j
- void "Test persist of association with proxy"() {
- given: "A domain model with a many-to-one"
- def person = new Person(firstName: "Fred", lastName: "Flintstone")
- person.save(flush:true)
- session.clear()
- def pet = new Pet(name: "Dino", owner: Person.load(person.id))
- pet.save(flush: true)
- session.clear()
-
- when: "The association is queried"
- pet = Pet.findByName("Dino")
-
- then: "The domain model is valid"
- pet != null
- pet.name == "Dino"
- pet.owner != null
- pet.owner.firstName == "Fred"
- }
-}

0 comments on commit ffb4b24

Please sign in to comment.
Something went wrong with that request. Please try again.