Wierne odtworzenie CREATE TABLE za pomocą adnotacji w encji

Antoni Kwapisz
20.08.2015

W SEAMie baza danych jest używana domyślnie za pośrednictwem Hibernate. Jedną z użytecznych cech Hibernata jest możliwość re-kreacji i tworzenia tabel w bazie danych na podstawie zdefiniowanych encji. Szczególnie się to przydaje podczas opracowywania/modyfikacji tabel oraz testowania zmian w nich.

W tym celu należy w profilu (tutaj plik resources/META-INF/persistence-[nazwa_profilu].xml) ustawić w tagu własność "hibernate.hbm2ddl.auto" na "create-drop". Wymusza to całkowitą rekreację tabel w bazie danych. W związku z tym ważne jest, by definicje tabeli były zgodne z zamierzeniami oraz z odpowiednikiem CREATE TABLE w języku SQL.

W poniższych przykładach użyjemy konwencji, zgodnie z którą wszelkie adnotacje są albo przy deklaracji klasy, albo przy deklaracji pól. Metody są pomijane i nie są pokazane w przykładach dla przejrzystości. Kod SQL podany został w dialekcie PostgreSQL.

Oto najprostszy przykład, definijący tabelę z identyfikatorem:

@Name("example1")
@Entity
@Scope(SESSION)
@Table(name = "example1_table")
public class Example1Tbl implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Id
  @Column
  private Long              id;

  ...
}

Znaczenie interesujących nas adnotacji:

  • @Entity - Informuje, że ta klasa jest encją.
  • @Table - Deklaruje tabelę. Nazwa tej tabeli jest podana w argumencie "name".
  • @Id - Informuje, ze to pole jest kluczem głównym.
  • @Column - Informuje, że to pole jest kolumną tabeli.

Przykład z zaimplementowaną autoinkrementacją klucza głównego:

@Name("example2")
@Entity
@Scope(SESSION)
@Table(name = "example2_table")
@SequenceGenerator(name = "example_seq", sequenceName = "example_seq", allocationSize = 1)
public class Example2Tbl implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Id
  @Column
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "example_seq")
  private Long              id;

  ...
}

Znaczenie nowych adnotacji:

  • @SequenceGenerator - definiuje nową sekwencję. "name" definiuje nazwę wewnętrzną sekwencji, "sequenceName" nazwę sekwencji w bazie danych, "allocationSize" opisuje, co ile ma się zmieniać id przy kolejnych insertach.
  • @GeneratedValue - wyznacza kolumnę, która będzie sekwencjonowana. "generator" musi mieć nazwę podaną w @SequenceGenerator.

Bardziej skomplikowany przykład, prezentujący kilka kombinacji definiowania kolumn tabeli z uwzględnieniem UNIQUE:

@Name("example3")
@Entity
@Scope(SESSION)
@Table(name = "example3_table",
  uniqueConstraints = @UniqueConstraint(columnNames = {"sometext", "someothertext" }))
public class Example3Tbl implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Id
  @Column(nullable = false)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "example_seq")
  private Long              id;

  @Column(nullable = true, length = 75)
  private String            sometext;

  @Column
  private String            someothertext;

  @Column(nullable = false, unique = true)
  private Integer         someinteger;

  @Lob
  @Column(nullable = false)
  private String            somelongtext;
  ...
}

Znaczenie nowych adnotacji/parametrów:

@Table:

  • uniqueConstraints - deklaruje pola, których kombinacja ma być unikalna. Zauważ, że to dotyczy kilku pól naraz. Do deklaracji pojedyńczego pola jako unikalnego użyj @Column(unique=true).

@Column:

  • nullable - informuje, czy pole może mieć null. W efekcie, nullable=false generuje NOT NULL. Domyślnie nullable = true.
  • length - długość/rozmiar pola. Zachowanie zalezy od klasy pola, w wypadku łańcucha tekstowego definiuje, ile znaków przeznaczone jest na to pole.
  • unique - true oznacza, ze to pole musi mieć wartość unikalną w tabeli.

@Lob - definiuje duży obiekt. Przy klasie String baza danych będzie miała typ pola "text" lub jego odpowiednik.

Ostatni przykład pokazuje, jak utworzyć klucze obce.

@Name("example4")
@Entity
@Scope(SESSION)
@Table(name = "example4_table")
public class Example4Tbl implements Serializable
{
  private static final long serialVersionUID = 1L;

  @Id
  @Column(nullable = false)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "example_seq")
  private Long              id;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "id_example3", nullable = false)
  private Example3Tbl  example3;
}

Nowe adnotacje:

  • @ManyToOne - informuje o typie powiązania.
  • @JoinColumn - jest podobny do @Column, lecz jest używany przy kluczach obcych. "name" opisuję nazwe pola.

Hibernate wie, do której tabeli dowiązać połączenie na podstawie klasy (tutaj Example3Tbl) pola.

Zgłoś swój pomysł na artykuł

Więcej w tym dziale Zobacz wszystkie