0

I need something like a partial contraint for one of my entities.

@Entity
public class MyEntity 
{
  @NotNull
  private String name;

  @ManyToOne @NotNull
  private Type type;
}

Only for a sinlge type I need the name to be unique.

Is this possible with a @UniqueConstraint or do I need to implement this with a @PrePersist and @PreUpdate listener? So far I haven't implemented such a listener, but even if I check the contraint in this listener, does it guarantee to prevent a duplicate entry?

Update

Let's assume the constraint should only be active for type=special

  • Allowed {id=1,type=normal,name=Test},{id=2,type=normal,name=Test}
  • Not allowed: {id=3,type=special,name=Test},{id=4,type=special,name=Test}

2 Answers 2

2

My understanding of the @UniqueContraint is that it may contain a list of column names that together define the uniqueness.

See: unique constraint check in JPA

   @UniqueConstraint(columnNames={"name", "type"}) 

I would expect this to enforce uniqueness across name and type. (No time to test though.)

Edit:

Aha. So now I understand the problem. How about this for an approach introduce a third attribute:

 int mySpecialValue;

This attribute has no public setter. Instead its value is set by the setType() with logic like this:

 public void setType(String theType){

      type = theType;          

      if ( "special".equals(type) ){
              mySpecialValue = 0;
      } else {
              mySpecialValue = makeUniqueInt(); // eg. some date twiddling
      }

 }

Now set the unique constraint to include the mySpecialValue. Hence for all specials the uniqueness depends entirely on the name, for others there is always a differentiator so the names can duplicate.

       Allowed {id=1,type=normal,name=Test, msv = 343223 },
                {id=2,type=normal,name=Test, msv = 777654 } <== not dup
       Not allowed: {id=3,type=special,name=Test, msv =0 },
                        {id=4,type=special,name=Test, msv =0} <== dup  
Sign up to request clarification or add additional context in comments.

3 Comments

How does it answer the question?
@djna Yes, that's also my understanding, I updated my example to demonstrate what I need.
@djna Interesting solution, but perfectly fits my needs. Thank you!
1

See conditional unique constraint for a similar question. I don't think a listener is the right place to define somthing like that. I would either implement it in the database, using a check constraint or a unique constraint on a view, or as a functional check in your application.

4 Comments

Thank you for this hint, I assume that I can manage it on database level, but I would prefereable implement this in JPA/Java.
Are you aware that @UniqueConstraint is only used to generate the database schema DDL? The constraint only exists in the database. It's in the database that it's checked, not in the JPA engine. If you implement it in Java, implement it as a functional check. But be aware that it won't prevent duplicates if two concurrent transactions make the check in parallel and then insert in parallel.
Yes, I'm aware of this. I should have written describe this in JPA. The database schema is created during development sometimes new and I will prevent the need of manual modifications. What if I do a functional check in a @Singleton bean? This should prevent parallel checks.
I wouldn't do this. As I said, the place of such a constraint is the database. If you cluster your application or use other ways than your JPA application to access the database, the constraint won't be enforced. And even then the singleton would be a contention point.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.