Jak każdy programista jestem leniwy, zamiast tworzyć mapowania w moim IDE o wiele lepiej wygenerować je wprost z bazy. W IntelliJ robi się łatwo o ile znajdziemy odpowiednią opcję o czym pisałem jakiś czas temu. Niestety szybko przekonałem się, że nie jest to idealne odwzorowanie moich tabel. Nie wiedzieć czemu IntelliJ zapomniał zaimportować sekwencje zadeklarowane w bazie, co skutkowało wystąpieniem szeregu błędów podczas prób zapisania danych w bazie, w szczególności wyróżnia się jeden:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.hibernate3.HibernateSystemException: ids for this class must be manually assigned before calling save(): com.darekzon.coffeine.domain.Category; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.darekzon.coffeine.domain.Category
Aby problemy przestały występować wystarczy z palca podpiąć sekwencje do konkretnego pola, robimy to przez zastosowanie adnotacji @GeneratedValue przy polu którego wartości mają być generowane przez sekwencje.
Kod wygląda następująco:
import javax.persistence.*; import java.io.Serializable; @Entity @Table(schema = "public", name = "category") public class Category implements Serializable { private Long id; @Id @Column(name = "id", nullable = false, length = 19) @SequenceGenerator(name = "category_seq", sequenceName = "category_id_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "category_seq") public Long getId() { return id; } public void setId(Long id) { this.id = id; } private String name; @Basic @Column(name = "name", nullable = false, length = 30) public String getName() { return name; } public void setName(String name) { this.name = name; } }
Pierwsze co robimy aby dodać generator to wskazanie która sekwencja generuje dane dla naszego pola, czyli adnotacja @SequenceGenerator, podajemy dla niej dwie wartości, pierwsza to nazwa sekwencji jaka obowiązywać będzie w zakresie naszej klasy, natomiast druga to nazwa sekwencji w bazie.
Po skonfigurowaniu sekwencji mówimy hibernate-owi, że nasze -pole będzie otrzymywać automatycznie wartość korzystając z @GeneratedValue. Dla adnotacji @GeneratedValue musimy podać strategię tworzenia nowych wartości (z racji, że jest to sekwencja wybieramy SEQUENCE) i oczywiście generator który te wartości będzie wskazywał, jako generator podajemy nazwę którą wcześniej wpisaliśmy w @SequenceGenerator.
Po tym zabiegu wszystko powinno działać jak trzeba.
Swoją drogą muszę się przestawić na tworzenie Entity Beanów a potem eksportowanie to do bazy danych, na pewno przyśpieszy to tworzenie projektu a przy okazji nie będę musiał tworzyć bazy danych (co uważam za zajęcie mało interesujące).
Jedno ale:
OdpowiedzUsuńJak nie dasz strategy = GenerationType.AUTO może się okazać, że Hibernate nie korzysta ze wskazanej sekwencji - i, z powodów, które są zupełnie niejasne i absolutnie tajemnicze, wartości klucza w tabeli zaczynają się od 5051 a sekwencja ani drgnie. Z drugiej strony wskazanie strategii AUTO, że ma korzystać z sekwencji użytkownika, a nie z ogólnej, na pierwszy rzut oka kompletnie nielogiczne, działa wyśmienicie.
Czary...
Pozdrawiam.
Tarrin