Mapim enum
We have already figured out how to map primitive data types: we use the @Column annotation and the @Type annotation . But not all cases can be covered by these annotations. And the most common case is enum .
Java enum objects can be stored in the database in two ways:
- as a number
- as a string
Let's write a small example where the user will have a favorite color, which is set using enum.
enum Color {
RED,
ORANGE,
YELLOW,
GREEN,
BLUE,
VIOLET
}
And add a color field to the User class :
@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;
}
If we want Hibernate to save the Color type to the base as numbers , then we need the fieldfavoriteColoradd annotation:
@Enumerated(EnumType.ORDINAL)
If we want the values to be stored as strings , then we need to add an annotation:
@Enumerated(EnumType.STRING)
Example:
@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;
}
Mapim Boolean
The second useful scenario is boolean type mapping. It just so happened historically that SQL does not have its own data type for Boolean and anything is used there instead.
The three most common options are:
- 1 or 0
- 'F' or 'T'
- 'Y' or 'N'
In general, if you are going to design your base, then it is better to write the BIT type right away. Well, the full mapping for it will look like this:
@Column(name = "is_correct", columnDefinition = "BIT")
@Type(type = "org.hibernate.type.NumericBooleanType")
private Boolean isCorrect;
Well, if you are not designing the database, then see the table above and think about how to correctly map the types you need.
Calculated fields
Sometimes the number of fields in an Entity class and the number of columns in a table do not match. There may be several reasons for this.
The most common is when there is some field in our Entity class that we do not want to save to the database. Everything is clear with this - just add the @Transient annotation to such a field and Hibernate will ignore it when working with the database.
Example:
@Entity(name = "Square")
public class Square {
@Id
public Long id;
public Integer width;
public Integer height;
@Transient
public Integer total;
}
This is a good option, but when reading an object from the database, the total field will be null. And we would like it to contain the product of width*height. This can also be done in Hibernate. There is a special @Formula annotation for this .
@Entity(name = "Square")
public class Square {
@Id
public Long id;
public Integer width;
public Integer height;
@Formula(value = " width * height ")
public Integer total;
}
Such a field will not be saved to the database, and when the object is read from the database, the value calculated by the formula will be written to it.
The SQL query will look something like this:
SELECT id, width, height, (width* height) AS total FROM Square;
@Embedded
Another useful annotation is @Embedded . It allows you to consider the fields of the child object as fields of the Entity class itself.
Let's say you have a User class and you decide to add an address to it:
@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;
}
Everything seems to be fine, but from the point of view of Java, it would be logical to put the address in a separate class. The address is still a separate entity. But how to do this if all this information is stored in the database in the user table?
The @Embedded annotation will help us . First, we will create the UserAddress class and put all the information on the user's address into it:
@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;
}
And then we use a field of this class in our User class :
@Entity
@Table(name="user")
class User
{
@Column(name="id")
public Integer id;
@Embedded
public UserAddress address;
@Column(name="created_date")
public Date createdDate;
}
Thanks to the @Embedded annotation, at the time of saving the object, Hibernate will understand that the fields of the UserAddress class need to be treated as fields of the User class itself .
Important! If you decide to add two UserAddress fields to your User class , then using @Embedded will no longer work: you will have duplicate fields and you will need to separate them somehow. This is done by overriding annotations: using the @AttributeOverrides annotation .
I want you to know this, but we won't go into detail here. I think this is enough for you to break your head. For the curious, I can leave a link to the official documentation .
GO TO FULL VERSION