Talk about Hibernate's mapping strategy

Source: Internet
Author: User
Tags access properties generator numeric locale
1 Basic Attribute Mappings

The JPA rule for persisted class properties is that if the properties of the persisted class are basic or basic type wrappers, such as String, BigInteger, BigDecimal, Java.util.Date, Java.util.Calendar, Java.sql.Date, Java.sql.Time, Java.sql.Timestamp, byte[], byte[], char[], character[], they will be automatically persisted. If a class adds @Embeddable annotations indicating that the class is part of some other class, it is an inline class, which we'll talk about later. If the property type is java.io.Serializable, then its value is stored in the serialized format. If none of the above conditions are true, Hibernate throws an exception at startup. 1.1 overriding default values for basic properties

If a property does not need to be persisted, you can add @javax. persistence.transient annotations or use the Java Transient keyword.

By default, all persisted properties are nullable and are optional. You can therefore use @Basic annotations to change a property to required, like this:

@Basic (optional = False)
BigDecimal Initialprice;

After this is configured, Hibernate will set this property to non-null when generating the SQL schema. If this property is null when inserting or updating, Hibernate throws an exception.

Most engineers prefer to use @Column annotations to declare non-null:

@Column (nullable = False)
BigDecimal Initialprice;

That is to say, @basic, @Column, and the @NotNull of the Bean Validation before it, they all function the same, and after configuring one of them, Hibernate validates the property non-null. It is recommended that you use the @NotNull of the Bean Validation, as this enables you to manually validate an Item instance at the presentation level.

For the contents of Bean Validation See the Hibernate Domain Model and library table structure design

@Column can also specify the name of the table field that needs to be mapped:

@Column (name = "Start_price", nullable = False)
BigDecimal Initialprice;

@Column also have some property settings, such as the ability to set the name of the catalog and schema, but they are rarely used in practice. 1.2 How to customize access properties

You can choose whether to access directly through the field or indirectly through the Getter/setter method.
Hibernate is based on the @Id annotations of the persistence class to determine exactly which method to take. For example @Id placed on a property, all properties will be accessed directly through the field.

The JPA specification also provides @Access annotations, which have two values, Accesstype.field (direct access via fields) and accesstype.property (accessed indirectly via the Getter/setter method). This annotation can be placed on a class so that it can be applied to all properties, or on a class property, with fine-grained control:

@Entity public
class Item {
    @Id
    @GeneratedValue (generator = constants.id_generator)
    protected Long Id ;

    @Access (Accesstype.property)
    @Column (name = "Item_name")//mapping is still expected here!
    protected String name;

     Public String GetName () {
        return name;
    }

    public void SetName (String name) {
        this.name =!name.startswith ("AUCTION:")? " AUCTION: "+ name:name;
    }
}

Hibernate also has a feature that can be used very rarely, mention here. NoOp-level accessors. Suppose a database table has a VALIDATED field that represents a valid time, but it is not placed in the domain class model (this should happen very rarely, O (∩_∩) o~). In order to be able to make a SQL query for this field, it must be placed in the Hbm.xml metadata file:

 

With this mapping, you can use validated in queries. Note that if you use Hibernate's hbm.xml metadata file for configuration, all persisted annotations on the Item class are invalidated.

If the above mappings do not meet the requirements, then you can customize a property accessor directly. Just implement a Org.hibernate.property.PropertyAccessor interface and configure it to the following note:

@org. Hibernate.annotations.AttributeAccessor ("My.custom.Accessor")

This is the Hibernate 4.3 + new feature. 1.3 using derived attributes

The value of this property is computed in real time after executing the SQL statement, and we can use the @org. Hibernate.annotations.Formula Annotations:

@org. Hibernate.annotations.Formula (
    "substr (DESCRIPTION, 1, 12) | | ' ... '
)
protected String shortdescription;

@org. Hibernate.annotations.Formula (
    "(select AVG (b.amount) from BID b where b.item_id = ID)"
)
protected BigDecimal Averagebidamount;

These properties are recalculated each time the Item is fetched from the database. Hibernate places these attributes into the select query as part of the query criteria. 1.4 Converting values of a column

Suppose the table has a field called Imperialweight, which represents the weight of the unit in points. But the important unit required by the application system is the kilogram, which needs to be configured by adding the conversion annotations:

@Column (name = "Imperialweight")
@org. Hibernate.annotations.ColumnTransformer (
    read = "imperialweight/ 2.20462 ",
    write ="? * 2.20462 "
)
protected double metricweight;

Once this is configured, it can be applied directly to the HQL:

list<item> result = Em.createquery ("Select I from I where I.metricweight =: w"). Setparameter ("W", 2.0). Getresultlist ();

Note: SQL statements that are generated in this manner may not be able to directly take advantage of the database configuration index. 1.5 default values for configuration Properties

The database can configure the default value for a field, and when new data is inserted, this field is set to the default value if the field does not have a new value set.

In general, when the database is automatically set to the default value for this field, the Hibernate framework should update the corresponding entity class instance. This can be achieved by configuring the @org. hibernate.annotations.Generated annotation Annotations:

@Temporal (Temporaltype.timestamp)
@Column (insertable = false, updatable = false)
@ org.hibernate.annotations.Generated (
    Org.hibernate.annotations.GenerationTime.ALWAYS
)
protected Date lastmodified;

@Column (insertable = False)
@org. Hibernate.annotations.ColumnDefault ("1.00")
@ org.hibernate.annotations.Generated (
     Org.hibernate.annotations.GenerationTime.INSERT
)
protected BigDecimal Initialprice;

Generationtime.always indicates that Hibernate will update the instance every time a new or updated SQL operation occurs. You can also configure the @Column (insertable = false, updatable = False) on the property so that this property becomes a read-only property, which means that this property can only be generated from the database.

@org. Hibernate.annotations.ColumnDefault is used to configure default values so that Hibernate will add the field defaults when exporting the SQL for the schema DDL. 1.6 Temporary Properties

Some properties, such as the timestamp property, are automatically generated by the database after the data is inserted, and then its value is no longer changed:

@Temporal (Temporaltype.timestmap)
@Column (updatable = false)
@ Org.hibernate.annotations.CreationTimestamp
protected Date createdon;

Java 8 API
protected Instant Reviewedon;

Hibernate supports the Java.time class package in/java 8.

The optional options for the Temporaltype in the @Temporal are date, time, and TIMESTAMP, which indicates when the property is stored in the database with the type of temporal field.

If no @Temporal annotations are configured here, Hibernate is set to Temporaltype.timestmap. @org. Hibernate.annotations.CreationTimestamp is inserted, the value is automatically generated by the database and hibernate is automatically refreshed. There is another @org. Hibernate.annotations.UpdateTimestamp annotations are similar to creationtimestamp annotations except that they are a change in the detection of data updates. 1.7 Mapping enumeration Types

Suppose you need an auction type:

public enum auctiontype{
        highest_bid,
        lowest_bid,
        fiexed_price
}

This can be mapped:

@NotNull
@Enumerated (enumtype.auctiontype)
protected Auctiontype auctiontype = auctiontype.highest_bid;

The default value for the @Enumerated is enumtype.ordinal, which is not good because ORDINAL is the sequence value of the elements in the enumeration (starting at 1), which is not clear when setting the default value. So it's best to configure it as
Enumtype.auctiontype. 2 mapping nested classes

Suppose that our user class has two attributes (home, billing) are the types of the Address class, that is, they are part of the user class (the image shows a whole and a part of the containment relationship). 2.1 Database Schema

The nested class Address does not have its own ID, because it must belong to a persisted class, such as the User class here. The life cycle of a nested class depends on its attribution class, and if the attribution class is saved, its nested classes are also saved. 2.2 Creating nested Classes

@Embeddable//instead of @Entity public class Address {@NotNull//ignored for DDL generation @Column (nullable = FA

    LSE)//used for DDL generation protected String Street;

    @NotNull @Column (nullable = False,length = 5) protected String zipcode;

    @NotNull @Column (nullable = false) protected String city; No-args constructor protected Address () {}/** * Convenience constructor * @param Street * @ Param zipcode * @param city */Public Address (String street, String ZipCode, String city) {This.str
        * * = Street;
        This.zipcode = ZipCode;
    this.city = City;
    } public String Getstreet () {return street;
    public void Setstreet (String street) {this.street = Street;
    } public String Getzipcode () {return zipcode;
    } public void Setzipcode (String zipcode) {this.zipcode = ZipCode; } public String getcity () {returnCity
    } public void Setcity (String city) {this.city = city; }
}
A nested class does not have a uniquely identified property. Hibernate invokes an argument-free constructor to create an instance. You can add a constructor with a parameter for easy invocation.

Note: the @NotNull attribute defined in the nested class is not used by Hibernate to generate the schema for the database. It will only be used to validate the bean at run time (Bean Validation). So we're going to use the @Column (nullable = false) to control the schema.

The following is the code for the main class:

@Entity
@Table (name = "USERS") Public
class User implements Serializable {

    @Id
    @GeneratedValue ( Generator = constants.id_generator)
    protected Long ID;

    Public Long getId () {
        return ID;
    }



    The Address is @Embeddable; No annotation is needed here.
    protected Address homeaddress;

    Public Address gethomeaddress () {
        return homeaddress;
    }

    public void sethomeaddress (Address homeaddress) {
        this.homeaddress = homeaddress;
    }


}

Hibernate is automatically detected because the Address class is a nested class.

A class that contains nested classes, with an example of its property access policy: If the @Entity of a nested class is configured with a field access mechanism-@Access (Accesstype.field), all its properties use the field mechanism. If the property access mechanism-@Access (Accesstype.property) is configured on the @Entity of a nested class, all its properties use the property access mechanism. If the main class adds a @Access (Accesstype.property) to the Getter/setter method of the property, it uses the property access mechanism. If you match the @Access to the main class, the access policy of the property is determined by the configuration.

When a User has no Address information, NULL is returned. 2.3 Overriding default properties for nested classes

Suppose the User class has a billingadress property, which is also the address type, which conflicts with the previous HomeAddress property, so we want it to overwrite:

@Embedded
@AttributeOverrides ({
        @AttributeOverride (name= "Street", column = @Column (name = "Billing_street") ),
        @AttributeOverride (name = "ZipCode", column = @Column (name =
                "Billing_zipcode", length = 5)),
        @ Attributeoverride (name = "City", column = @Column (name = "Billing_city"))
})
protected Address billingaddress;< C7/>public Address getbillingaddress () {
    return billingaddress;
}

public void setbillingaddress (Address billingaddress) {
    this.billingaddress = billingaddress;
}

@Embedded is actually superfluous here, it may only be useful if you need to map a class for a third-party package.

@AttributeOverrides overrides the configuration in the nested class, in the example we mapped the three properties in the nested class to three different fields. 2.4 Mapping Multilayer nested classes

Suppose we define multiple levels of nested classes, address is a nested class of User, and city is a nested class of Address:

Address class:

@Embeddable public
class Address {

    @NotNull
    @Column (nullable = False)
    protected String Street;

    @NotNull
    @AttributeOverrides (
            @AttributeOverride (name = "Name", column = @Column (name = "City", Nullable = False ))
    protected City City
    ;

    Public String Getstreet () {
        return street;
    }

    public void Setstreet (String street) {
        this.street = Street;
    }

    Public City Getcity () {
        return city;
    }

    public void Setcity (city city) {
        this.city = city;
    }
}

City class:

@Embeddable public
class City {

    @NotNull
    @Column (nullable = false, length = 5)//override VARCHAR (255) c25/>protected String ZipCode;

    @NotNull
    @Column (nullable = False)
    protected String name;

    @NotNull
    @Column (nullable = False)
    protected String country;
}

Hibernate will straighten out the relationship between nested hierarchies, regardless of how deep they are defined.

You can add @AttributeOverrides to the class properties at any level, overriding the default column name mappings. These levels can all use point syntax, like this: Address#city#name. 2.5 using converters to implement mappings from Java type to SQL type 2.5.1 Built-in type 2.5.1.1 native and numeric types

name Java Type ANSI SQL Type
Integer int, Java.lang.Integer INTEGER
Long Long, Java.lang.Long BIGINT
Short Short, Java.lang.Short SMALLINT
Float float, java.lang.Float FLOAT
Double Double, java.lang.Double DOUBLE
Byte BYTE, Java.lang.Byte TINYINT
Boolean Boolean, Java.lang.Boolean BOOLEAN
Big_decimal Java.math.BigDecimal NUMERIC
Big_integer Java.math.BigInteger NUMERIC

The name here refers to the name of the Hibernate definition, which is used in subsequent custom type mappings.

Hibernate converts the ANSI SQL type to the actual configured database dialect type.

The

NUMERIC type contains the integer digits and precision, and for a BigDecimal property, it corresponds to a type of NUMERIC (19,2). You can use @Column fine-grained control over the number of integers and precision. 2.5.1.2 Character Type

/tr>
name Java type ansi SQL type
string java.lang.String VARCHAR
character char[], character[], java.lang.String CHAR
yes_no bollean, Java.lang.Boolean CHAR (1), ' Y ' or ' N '
true_false bollean, Java.lang.Boolean CHAR (1), ' T ' or ' F '
class java.lang.Class VARCHAR
locale java.util.Locale VARCHAR
timezone java.util.TimeZone VARCHAR
currency java.util.Currency VARCHAR

Hibernate automatically selects the most appropriate string type for the property after using @Column (length= ...) or @Length labeling the property. For example, MySQL database, if the length is within 65535, will choose the VARCHAR type, if the length between 65536 ~ 16777215, will choose the Mediumtext type, longer properties will choose the Longtext type. 2.5.1.3 Date and Time type

name Java Type ANSI SQL Type
Date Java.util.Date, Java.sql.Date DATE
Time Java.util.Date, Java.sql.Time Time
Timestamp Java.util.Date, Java.sql.Timestamp TIMESTAMP
Calendar Java.util.Calendar TIMESTAMP
Calendar_date Java.util.Calendar DATE
Duration Java.time.Duration BIGINT
Instant Java.time.Instant TIMESTAMP
LocalDateTime Java.time.LocalDateTime TIMESTAMP
Localdate Java.time.LocalDate DATE
LocalTime Java.time.LocalTime Time
Offsetdatetime Java.time.OffsetDateTime TIMESTAMP
Offsettime Java.time.OffsetTime Time
Zonedatetime Java.time.ZonedDateTime TIMESTAMP

The list contains the Java 8 Java.time API, which is unique to Hibernate and is not included in JPA 2.1.

If a value of type java.util.Date is stored, the value type is java.sql.Date when obtained. This may cause problems when comparing objects for equality. To convert the time to a Unix millisecond time, use this method to compare:
Adate.gettime () > Bdate.gettime ()

Especially in collections (such as HashSet) that contain java.util.Date, java.sql.date| time| Timestamp, differences in element comparison methods. The best way is to keep the type consistent. 2.5.1.4 binary types and big data types

name Java Type ANSI SQL Type
Binary Byte[], java.lang.byte[] VARCHAR
Text Java.lang.String Clob
Clob Java.lang.Clob Clob
Serializable Java.io.Serializable VARBINARY

The VARBINARY type is a database that relies on the actual configuration.

There is a handy @Lob in JPA:

@Entity public
class Item {

    @Lob
    protected byte[] image;

    @Lob
    protected String Descripton;
}

This will map byte[] to the BlOB type and the String to the CLOB type. Unfortunately, this does not enable lazy loading of big data fields.

Therefore, it is recommended to use JAVA.SQL.CLOB and Java.sql.Blob types for lazy loading:

@Entity public
class Item {

    @Lob
    protected java.sql.Blob image;

    @Lob
    protected Java.sql.Clob Descripton;
}

You can even read a field of a large data type through a byte stream:

Item item = Em.find (Item.class, item_id);

You can stream the bytes directly
... InputStream Imagedatastream = Item.getimageblob (). Getbinarystream ();

or materialize them to memory:
bytearrayoutputstream outputstream = new Bytearrayoutputstream ();
Streamutils.copy (Imagedatastream, outputstream);
byte[] imagebytes = Outputstream.tobytearray ();

Hibernate also provides a number of convenient ways to read fixed byte-length data directly from InputStream for persistent operations, which does not consume memory:

Need the native Hibernate API
Session session = Em.unwrap (Session.class);
You need to know the number of bytes you want to read from the stream!
Blob blob = Session.getlobhelper (). Createblob (Imageinputstream, bytelength);

Someitem.setimageblob (BLOB);
Em.persist (Someitem);

This will store the byte stream data as a field of type VARBINARY. 2.5.1.5 Selecting a type adapter

You can explicitly configure a special adapter annotation:

@Entity public
class item{
    @org. Hibernate.annotations.Type (Type = "yes_no")
    protected Boolean verified = false;
}

After this is configured, the Boolean value is converted to Y or N before being stored. 2.5.2 Creating a custom JPA converter

In our online auction system, a new requirement is required to enable the system to support multiple currency computing functions. The traditional approach is to modify the table structure and then modify the corresponding code. Another way is to use a custom JPA converter.

public class Monetaryamount implements Serializable {protected final BigDecimal value;

    Protected final Currency Currency;
        Public Monetaryamount (BigDecimal value, Currency Currency) {this.value = value;
    this.currency = currency;
    } public BigDecimal GetValue () {return value; } public Currency 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.