Skip to content

Commit 45216eb

Browse files
puneetbehlgraemerocher
authored andcommitted
#1263 Fix issue with UniqueConstraint (#1276)
Fetch identifier using ProxyHandler if the association is a proxy.
1 parent 3e9ce32 commit 45216eb

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/validation/UniqueConstraintSpec.groovy

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,30 @@ class UniqueConstraintSpec extends Specification {
5454

5555
}
5656

57+
void "test unique constraint checks parent field"() {
58+
59+
setup:
60+
Organization organization = new Organization(name: "Test Org")
61+
organization.defaultChannel.organization = organization
62+
organization.addToChannels(name: "Foo")
63+
organization.addToChannels(name: "Bar")
64+
organization.save(flush: true, failOnError: true)
65+
datastore.currentSession.clear()
66+
67+
when: "we change the channel name to an existing channel name in the organization"
68+
Channel channel = Channel.findByName("Bar")
69+
channel.name = "Foo"
70+
71+
then:
72+
!channel.validate()
73+
channel.hasErrors()
74+
channel.errors.getFieldError('name').code == 'unique'
75+
76+
cleanup:
77+
Channel.deleteAll()
78+
Organization.deleteAll(organization)
79+
}
80+
5781
void 'unique constraint works with parent/child/child'() {
5882
given: 'an existing channel'
5983
def testOrg = new Organization(name: 'Test 1')
@@ -120,7 +144,7 @@ class UniqueConstraintSpec extends Specification {
120144

121145

122146
@Entity
123-
abstract class Channel {
147+
class Channel {
124148

125149
String name
126150
static belongsTo = [organization: Organization]
@@ -165,4 +189,5 @@ class Organization {
165189
DefaultChannel defaultChannel = new DefaultChannel()
166190

167191
static hasOne = [defaultChannel: DefaultChannel]
192+
static hasMany = [channels: Channel]
168193
}

grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/validation/constraints/builtin/UniqueConstraint.groovy

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.grails.datastore.mapping.model.PersistentEntity
99
import org.grails.datastore.mapping.model.PersistentProperty
1010
import org.grails.datastore.mapping.model.types.Association
1111
import org.grails.datastore.mapping.model.types.ToOne
12+
import org.grails.datastore.mapping.proxy.ProxyHandler
1213
import org.grails.datastore.mapping.reflect.EntityReflector
1314
import org.springframework.context.MessageSource
1415
import org.springframework.validation.Errors
@@ -103,6 +104,7 @@ class UniqueConstraint extends AbstractConstraint {
103104

104105
if (constraintParameter) {
105106
boolean shouldValidate = true
107+
final ProxyHandler proxyHandler = targetEntity.getMappingContext().proxyHandler
106108
detachedCriteria = detachedCriteria.build {
107109
eq(constraintPropertyName, propertyValue)
108110
if (!group.isEmpty()) {
@@ -113,7 +115,12 @@ class UniqueConstraint extends AbstractConstraint {
113115
PersistentProperty associated = targetEntity.getPropertyByName(propName)
114116
if (associated instanceof ToOne) {
115117
// We are merely verifying that the object is not transient here
116-
def associationId = ((Association) associated).getAssociatedEntity().getReflector().getIdentifier(value)
118+
def associationId
119+
if (proxyHandler.isProxy(value)) {
120+
associationId = proxyHandler.getIdentifier(value)
121+
} else {
122+
associationId = ((Association) associated).getAssociatedEntity().getReflector().getIdentifier(value)
123+
}
117124
if (associationId == null) {
118125
// no need to validate since this group association is unsaved
119126
shouldValidate = false

0 commit comments

Comments
 (0)