Hibernate Learning Notes 2
1. summary
This paper mainly introduces how to deal with the following problems:
- Mapping of Enumerated Types
- Mapping of Time Type
- Custom Property Mapping in JPA
- Automatic generation parameters (such as insertion time of automatically generated data, update time of automatically generated data)
2. Domain Model
1.1. Basic Type
Last article Basic Type In this section, you've learned how to customize Basic Type. This section continues to learn some ways of type mapping.
1.1.1. Mapping of Enumeration Types
First, we introduce the mapping of enumeration types. Simply add the @Enumerated annotation to the variable of the enumeration type, which has a parameter indicating what information to store in the database for the enumeration; there are two optional values:
- ORDINAL: The sequential index of the enumeration at definition is used as the storage value.
- STRING: Use the name of the enumeration as the storage value.
For chestnuts, we add a gender attribute to the previous User enumeration type, which is defined as follows:
public enum Gender { FEMALE, MALE }
Next, add the gender attribute to User, and we want to save the enumerated literal values directly to the database, so do this:
@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @Type(type = "String[]") private String[] hobbies; @Enumerated(EnumType.STRING) private Gender gender; ... }
You can also try to modify the annotation parameter EnumType.STRING as EnumType.ORDINAL, the test method is not given, that is, to work out the enumeration method.
1.1.2. Mapping of LOBs type
Because I seldom enter binary data directly into the database, so I did not learn this way. Seeing what you want to learn Official documents.
1.1.3. Time Type Mapping
Three time types are defined in standard SQL:
- DATE: Date (year, month, day)
- TIME: Time (hours and seconds)
- TIMESTAMP: Represents the date and time and contains nanoseconds.
In Java, we usually use java.util.Date and java.util.Calendar to represent time. In addition, Java 8 defines a wealth of time-related classes under the java.time package.
Like enumeration types, we need only a @Temporal annotation to map. It has a parameter that specifies the sql time type of the mapping, and the values are the three mentioned above.
1.1.4. JPA 2.1 AttributeConverters
In the last blog, we learned how to customize Basic Type To handle type mappings that Hibernate does not support. In fact, JPA 2.1 defines the AttributeConverters interface to do this, and Hibernate supports it. Here's a chestnut to illustrate its usage, or the previous one that saved String [] as a json string in the database.
Defining a transformation class StringArrayConverter requires the implementation of the AttributeConverters interface
@Converter public class StringArrayConverter implements AttributeConverter<String[], String> { @Override public String convertToDatabaseColumn(String[] attribute) { return JSON.toJSONString(attribute); } @Override public String[] convertToEntityAttribute(String dbData) { JSONArray jsonArray = JSON.parseArray(dbData); String[] result = new String[jsonArray.size()]; for (int i = 0; i < result.length; i++) { result[i] = jsonArray.getString(i); } return result; } }
Then use the @Convert annotation on User's hobbies property:
@Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @Convert(converter = StringArrayConverter.class) private String[] hobbies; @Enumerated(EnumType.STRING) private Gender gender; ... }
PS: After testing, the above method is OK, but when using Idea, a mistake was reported: "Basic attribute type should be" String []", which does not affect the operation, but it is annoying. Please tell me the cause of the children's shoes.
1.1.5. Generated properties
Sometimes we want some fields to be generated automatically, instead of specifying them manually each time, we can use the Generated properties feature.
For example, we sometimes need to save the time when each record in the database was created and updated. We can do this:
First, we define a generator that tells Hibernate how to automatically generate data, which requires the implementation of the ValueGenerator < T > interface:
public class LoggedDateGenerator implements ValueGenerator<Date> { @Override public Date generateValue(Session session, Object owner) { return new Date(); } }
The above needs to implement the generateValue method. The return value of this method is the value to be generated. Here we simply return the current date (in fact, it is better to judge whether updated is empty, if it is empty, it means that it is the first time to create, we should assign the creation to update (provided that the creation is not empty), otherwise it may lead to the time when the data insertion is created and the upda. The time of Ted is inconsistent. One of the two parameters is the Session we are familiar with, and the other is the object that Session manipulates during insert and uodate operations.
Then you can use it, or have User as an example, add the create and update attributes to it:
@GeneratorType(type = LoggedDateGenerator.class, when = GenerationTime.INSERT) @Temporal(TemporalType.TIMESTAMP) private Date created; @GeneratorType(type = LoggedDateGenerator.class, when = GenerationTime.ALWAYS) @Temporal(TemporalType.TIMESTAMP) private Date updated;
We add generators for attributes by @GeneratorType and specify the timing of generation:
- Generation Timing. NEVER: This means that no generator is used. It's the default value.
- Generation Timing. INSERT: Represents the use of generators to generate data only when inserting.
- Generation Timing. ALWAYS: Represents that data is always generated using generators.
@ Temporal, as described above, is used to map time types.
In fact, Hibernate takes into account the universality of the above operations and therefore provides direct annotation support by simply replacing the above annotations with the following:
@CreationTimestamp private Date created; @UpdateTimestamp private Date updated;
We can also use Generation to do the above work. Note the difference between Generator and Generator. In fact, Generation relies on Generator (not necessarily), and is more flexible than Generator. The following is how Generation is implemented:
First, we need to define an annotation class, such as Creation Timestamp. What we need is that the attribute marked by this annotation automatically generates a timestamp at insertion time, and the timestamp data is generated by the database:
`@Retention(RetentionPolicy.RUNTIME) @ValueGenerationType(generatedBy = CreationValueGeneration.class) public @interface CreationTimestamp { }
@ Needless to say, the Retention annotation is to define when annotations are saved. @ The Value Generation Type annotation is used to specify Generation.
The following is the implementation of Generation:
public class CreationValueGeneration implements AnnotationValueGeneration<CreationTimestamp> { @Override public void initialize(CreationTimestamp annotation, Class<?> propertyType) { } /** * The return value determines the timing of data generation, as before. */ public GenerationTiming getGenerationTiming() { return GenerationTiming.INSERT; } /** * Returns a Generator. If you want the database to generate values, you can also return null */ public ValueGenerator<?> getValueGenerator() { return null; } /** * The return value indicates whether the column is included in sql */ public boolean referenceColumnInSql() { return true; } /** * The return value represents the value used by the column in the sql statement */ public String getDatabaseGeneratedReferencedColumnValue() { return "current_timestamp"; } }
In this way, it can be used:
@CreationTimestamp private Date created;
If you want Hibernate to generate timestamps as before, you can modify the method of Generation implementation classes:
public GenerationTiming getGenerationTiming() { return GenerationTiming.INSERT; } public ValueGenerator<?> getValueGenerator() { return (session, owner) -> new Date( ); } public boolean referenceColumnInSql() { return false; } public String getDatabaseGeneratedReferencedColumnValue() { return null; }