Skip to content

Unique constraint defined in child classes for inherited field is applied globally #14540

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
4 tasks done
dpcasady opened this issue Dec 3, 2018 · 1 comment
Open
4 tasks done

Comments

@dpcasady
Copy link
Contributor

dpcasady commented Dec 3, 2018

The detailed functionality (especially in edge cases dealing with inheritance) of unique constraints has changed back and forth over the last couple of years. As of 6.1.11, this behavior has changed again.

Task List

  • Steps to reproduce provided
  • Stacktrace (if present) provided
  • Example that reproduces the problem uploaded to Github
  • Full description of the issue provided (see below)

Steps to Reproduce

  1. Create a parent domain class with at least one field (e.g., name)
  2. Create 2 child domain classes that each define a unique constraint for the inherited name field
  3. Create an instance of each child class and set their name fields to the same value
  4. Persist both instances

Here's an example of what the domains might look like:

class Parent {
    String name
}

class Child1 extends Parent {
    static constraints = {
        name unique: true
    }
}

class Child2 extends Parent {
    static constraints = {
        name unique: true
    }
}

And the unexpected behavior:

def child1 = new Child1(name: 'test').save()
def child2 = new Child2(name: 'test').save() // validation fails

Expected Behaviour

Although the name field is declared in the parent class, the unique constraints are defined in the child classes, so one would expect that only duplicate values within the same child class would cause validation to fail. When searching for duplicate instances, it shouldn't matter where the field is declared, only where the constraint is defined. This is how things have worked as of late up until 6.1.11.

Actual Behaviour

In reality, the unique constraint finds the class that declares the constrained property and assumes that that class is also the one that defines the constraint. After persisting an instance of one child class, an instance of the other child class with the same name value fails validation. This would be the expected behavior if the constraint was also defined in the parent class, but that's not the case.

Unfortunately, the fix for a recent issue caused this issue to arise. I can see how this is a tricky problem. Constraints should have the ability to be inherited, but i don't believe that we should assume that the class that declares the field also defines the constraint. Currently, a constraint only has a reference to the constraint owning class, but not to the constraint defining class. If there was a reference to the constraint defining class, we could check if the constraint defining class and the class that declares the field are the same before automatically using the class that declares the field in the unique constraint criteria.

I'd be happy to work on a pull request but wanted to get some feedback first.

Environment Information

  • Operating System: MacOS
  • GORM Version: 6.1.11
  • Grails Version (if using Grails): 3.3.8
  • JDK Version: 1.8

Example Application

https://github.com/dpcasady/unique-constraint-inheritance

@dpcasady
Copy link
Contributor Author

dpcasady commented Jan 2, 2019

Any thoughts on this? Like I said, I'd be happy to attempt a fix if you think it's worthwhile.

@jdaugherty jdaugherty transferred this issue from apache/grails-data-mapping Apr 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants