Wyliczenie mapy
Dowiedzieliśmy się już, jak mapować prymitywne typy danych: używamy adnotacji @Column i adnotacji @Type . Ale nie wszystkie przypadki mogą być objęte tymi adnotacjami. A najczęstszym przypadkiem jest enum .
Obiekty Java enum mogą być przechowywane w bazie danych na dwa sposoby:
- jako liczba
- jako ciąg
Napiszmy mały przykład, w którym użytkownik będzie miał ulubiony kolor, który jest ustawiany za pomocą enum.
enum Color {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET
}
I dodaj pole koloru do klasy User :
@Entity
@Table(name="user")
class User
{
@Column(name="id")
public Integer id;
@Column(name="favorite_color")
public Color favoriteColor;
@Column(name="created_date")
public Date createdDate;
}
Jeśli chcemy, aby Hibernate zapisał typ Color do bazy jako liczby , potrzebujemy polaulubiony kolordodaj adnotację:
@Enumerated(EnumType.ORDINAL)
Jeśli chcemy, aby wartości były przechowywane jako stringi , musimy dodać adnotację:
@Enumerated(EnumType.STRING)
Przykład:
@Entity
@Table(name="user")
class User
{
@Column(name="id")
public Integer id;
@Enumerated(EnumType.ORDINAL) //value will be saved to the base as a number
@Column(name="favorite_color")
public Color favoriteColor;
@Column(name="created_date")
public Date createdDate;
}
Mapuj Boolean
Drugim użytecznym scenariuszem jest mapowanie typu boolowskiego. Historycznie tak się złożyło, że SQL nie ma własnego typu danych dla Boolean i zamiast tego używa się wszystkiego.
Trzy najczęstsze opcje to:
- 1 lub 0
- „F” lub „T”
- „T” lub „N”
Ogólnie rzecz biorąc, jeśli zamierzasz zaprojektować swoją bazę, lepiej od razu napisać typ BIT. Cóż, pełne mapowanie będzie wyglądać tak:
@Column(name = "is_correct", columnDefinition = "BIT")
@Type(type = "org.hibernate.type.NumericBooleanType")
private Boolean isCorrect;
Cóż, jeśli nie projektujesz bazy danych, spójrz na powyższą tabelę i zastanów się, jak poprawnie zmapować potrzebne typy.
Obliczone pola
Czasami liczba pól w klasie Entity i liczba kolumn w tabeli nie są zgodne. Przyczyn może być kilka.
Najczęściej występuje, gdy w naszej klasie Entity jest jakieś pole, którego nie chcemy zapisywać do bazy danych. Z tym wszystko jest jasne - wystarczy dodać adnotację @Transient do takiego pola , a Hibernate zignoruje ją podczas pracy z bazą danych.
Przykład:
@Entity(name = "Square")
public class Square {
@Id
public Long id;
public Integer width;
public Integer height;
@Transient
public Integer total;
}
Jest to dobra opcja, ale podczas wczytywania obiektu z bazy danych pole total będzie miało wartość null. Chcielibyśmy, aby zawierał iloczyn szerokość * wysokość. Można to również zrobić w trybie hibernacji. Jest do tego specjalna adnotacja @Formula .
@Entity(name = "Square")
public class Square {
@Id
public Long id;
public Integer width;
public Integer height;
@Formula(value = " width * height ")
public Integer total;
}
Takie pole nie zostanie zapisane do bazy danych, a gdy obiekt zostanie odczytany z bazy danych, zostanie do niego wpisana wartość wyliczona przez formułę.
Zapytanie SQL będzie wyglądać mniej więcej tak:
SELECT id, width, height, (width* height) AS total FROM Square;
@Osadzony
Inną użyteczną adnotacją jest @Embedded . Pozwala traktować pola obiektu potomnego jako pola samej klasy Entity.
Załóżmy, że masz klasę User i decydujesz się dodać do niej adres:
@Entity
@Table(name="user")
class User
{
@Column(name="id")
public Integer id;
@Column(name="user_address_country")
public String country;
@Column(name="user_address_city")
public String city;
@Column(name="user_address_street")
public String street;
@Column(name="user_address_home")
public String home;
@Column(name="created_date")
public Date createdDate;
}
Wszystko wydaje się być w porządku, ale z punktu widzenia Javy logiczne byłoby umieszczenie adresu w osobnej klasie. Adres jest nadal odrębną jednostką. Ale jak to zrobić, jeśli wszystkie te informacje są przechowywane w bazie danych w tabeli użytkownika?
Pomoże nam w tym adnotacja @Embedded . Najpierw utworzymy klasę UserAddress i umieścimy w niej wszystkie informacje o adresie użytkownika:
@Embeddable
class UserAddress
{
@Column(name="user_address_country")
public String country;
@Column(name="user_address_city")
public String city;
@Column(name="user_address_street")
public String street;
@Column(name="user_address_home")
public String home;
}
Następnie używamy pola tej klasy w naszej klasie User :
@Entity
@Table(name="user")
class User
{
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Dzięki adnotacji @Embedded , w momencie zapisywania obiektu, Hibernate zrozumie, że pola klasy UserAddress należy traktować jak pola samej klasy User .
Ważny! Jeśli zdecydujesz się dodać dwa pola UserAddress do swojej klasy User , to użycie @Embedded przestanie działać: będziesz mieć zduplikowane pola i będziesz musiał je jakoś rozdzielić. Odbywa się to poprzez zastąpienie adnotacji: za pomocą adnotacji @AttributeOverrides .
Chcę, żebyś to wiedział, ale nie będziemy tutaj wchodzić w szczegóły. Myślę, że to wystarczy, żebyś rozbił sobie głowę. Dla ciekawskich mogę zostawić link do oficjalnej dokumentacji .
GO TO FULL VERSION