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 .