Hibernate Annotations - Case Insensitive UniqueConstraint

后端 未结 2 1400
失恋的感觉
失恋的感觉 2021-01-05 04:54

I have an entity annotated with the following:

@Entity
@Table(uniqueConstraints={@UniqueConstraint(columnNames={\"name\"})})
public class Component extends M         


        
相关标签:
2条回答
  • 2021-01-05 05:49

    With PostgreSQL, you would indeed do something like this to implement your requirement:

    CREATE UNIQUE INDEX My_Index on Component (lower(name));
    

    But there is to my knowledge no way to achieve this using annotations.

    The only option I can think of if you want to rely on Hibernate's hbm2ddl tool to generate the schema and still have that index created would be to leverage the import.sql feature. From the Rotterdam JBug and Hibernate's import.sql blog post:

    import.sql: easily import data in your unit tests

    Hibernate has a neat little feature that is heavily under-documented and unknown. You can execute an SQL script during the SessionFactory creation right after the database schema generation to import data in a fresh database. You just need to add a file named import.sql in your classpath root and set either create or create-drop as your hibernate.hbm2ddl.auto property.

    I use it for Hibernate Search in Action now that I have started the query chapter. It initializes my database with a fresh set of data for my unit tests. JBoss Seam also uses it a lot in the various examples. import.sql is a very simple feature but is quite useful at time. Remember that the SQL might be dependent on your database (ah portability!).

    #import.sql file
    delete from PRODUCTS
    insert into PRODUCTS (PROD_ID, ASIN, TITLE, PRICE, IMAGE_URL, DESCRIPTION) values ('1', '630522577X', 'My Fair Lady', 19.98, '630522577X.jpg', 'My Fair blah blah...');
    insert into PRODUCTS (PROD_ID, ASIN, TITLE, PRICE, IMAGE_URL, DESCRIPTION) values ('2', 'B00003CXCD', 'Roman Holiday ', 12.98, 'B00003CXCD.jpg', 'We could argue that blah blah');
    

    For more information about this feature, check Eyal's blog (Updated Location for dead link), he wrote a nice little entry about it. Remember if you want to add additional database objects (indexes, tables and so on), you can also use the auxiliary database objects feature.

    0 讨论(0)
  • 2021-01-05 06:00

    I would suggest attacking this problem from a different angle:

    1. add a new column, internal one, call it lcname (stands for lower-cased name)

      @NotEmpty
      @Column(nullable = false)
      private String lcname;
      
    2. change the constraint you set as annotation to use the new field instead :

      @Entity
      @Table(uniqueConstraints={@UniqueConstraint(columnNames={"lcname"})})
      public class Component extends Model {
          ...
      }
      
    3. modify the name setter to also set lcname with a lower case of the original name provided by the client

      public void setName(String name) {
          this.name = name;
          this.lcname = name.toLowerCase();
      }
      

    That's it. Every time the entity will be persisted, also a lower cased name will be saved. That way if you save "A" you'll have a record with lcname = "a" saved, and next time you try to save an entity with name "a" the operation will fail due to the constraint on lcname The change is completely transparent to anyone who fetches an entity from the database since lcname is private and there is no getter for it, while the original getName will return the original name as provided initially by the client who created it.

    0 讨论(0)
提交回复
热议问题