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}
Thor
  • 6,607
  • 13
  • 62
  • 96

2 Answers2

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  
Community
  • 1
  • 1
djna
  • 54,992
  • 14
  • 74
  • 117
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.

Community
  • 1
  • 1
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thank you for this hint, I assume that I can manage it on database level, but I would prefereable implement this in JPA/Java. – Thor Jul 05 '11 at 13:06
  • 2
    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. – JB Nizet Jul 05 '11 at 13:17
  • 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. – Thor Jul 05 '11 at 13:30
  • 1
    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. – JB Nizet Jul 05 '11 at 13:38