kmansoor
kmansoor

Reputation: 4345

Naming a multi-column constraint using JPA

The name attribute of @UniqueConstraint seems to have no effect.

@Entity
@Table(name = "TAG", uniqueConstraints = @UniqueConstraint(columnNames = {
        "TAG_NAME", "USERS_ID" }, name="UQ_TAG_USER"))
public class Tag extends BaseEntity {

}

I'm usning SQL Server 2008, JPA 2.0 with Hibernate 3.6.

On the DB side an index, UQ__TAG__6EF57B66 is created instead of UQ_TAG_USER.

What am I missing? is there no way to enforce a given name from java side? and one must resort to editing schema files? we are a small shop without a DBA and I try to make do as much as I can by the help of hibernate schema facilities.

Upvotes: 1

Views: 1007

Answers (1)

m_vitaly
m_vitaly

Reputation: 11952

I assume you are using hibernate because you have it in the tags for this question. It's a bug/missing feature in hibernate:

https://hibernate.onjira.com/browse/HB-1245

It will simply ignore the unique constraint name when the dialect supports creating the constraint in the same statement as create table. I've checked SqlServer and Oracle dialects and they both support this way of creating the constraint, that will cause the bug you are experiencing.

There are two ways to workaround this bug:

1. The quick way:
Just extend the dialect and return false for supportsUniqueConstraintInCreateAlterTable() method:

public static class SQLServerDialectImproved extends SQLServerDialect {
    @Override
    public boolean supportsUniqueConstraintInCreateAlterTable() {
        return false;
    }
}

And set this class as your dialect in hibernate.dialect property of the persistence unit configuration (persistence.xml).

2. The right way:
Fix the hibernate code and recompile:
The bug is at org.hibernate.mapping.UniqueKey class, the method sqlConstraintString() will return unique (TAG_NAME, USERS_ID) for all dialects, even if they support constraint UQ_TAG_USER unique (TAG_NAME, USERS_ID).
But that is probably a larger change (need to support all kinds of dialects, etc.)

Under the hood:
If you use the original dialect, it will cause the following sql statement to be executed to create the table (added id column):

create table TAG (
    id bigint not null,
    TAG_NAME varchar(255),
    USERS_ID varchar(255),
    primary key (id),
    unique (TAG_NAME, USERS_ID)
)

And after you apply the fix as stated in first option the following sql statements will be executed:

create table TAG (
    id numeric(19,0) not null,
    TAG_NAME varchar(255),
    USERS_ID varchar(255),
    primary key (id)
)

create unique index UQ_TAG_USER on TAG (TAG_NAME, USERS_ID)

which include the creation of the unique constraint with the chosen name (UQ_TAG_USER) in a separate statement.

Upvotes: 3

Related Questions