JPA – Associations @OneToOne , @OneToMany, @ManyToOne, @ManyToMany part 3

Previously I wrote about OneToMany and ManyToOne and OneToOne associations, in this post I will show you how to handle ManyToMany associations.

Example that I will be using is classical example of many to many association where we have a teacher that can can teach  many students and a student that can be thought by multiple teachers. To do this I have created two entities Teacher and Student :

 

When many to many association is created we will have three tables STUDENT and TEACHER and TEACHER_STUDENT. Last one binds two tables together with two foreign keys STUDENT_FK_ and TEACHER_FK_ pointing to their primary keys.

Observe how to setup owning side of the association with @JoinTable you can specify table name and with two @JoinColumn one for owning and inverse side. Both JoinColumn specify names for foreign keys.

 

Unit Test

To make sure all works tests should always be created

It is important to note that both sides must be updated in order to make all work properly. Here are those two lines.

This covers all JPA associations types.

 

 

JPA – Associations @OneToOne , @OneToMany, @ManyToOne, @ManyToMany part 2

In previous post I wrote about @OneOnOne association, now I will go trough oneToMany and manyToOne associations with examples.

This associations are used to present that list of entities are part of other “bigger” entity, for example company can have several departments. Department is the part of the company and company is consisted of several departments.

Import is to note that if company is deleted then department is destroyed as well. Why is this important? Because if you setup cascade in the wrong way you might delete important information from your database.

Entities

 

There is detailed explanation in previous post about annotations @Entity, @Table, @Id, @Column, @GeneratedValue so I will focus only on @OneToMany and @ManyToOne.

There are two sides of the coin same as there are two sides of association, there is owning side and inverse side, one side has joinColumn and other has mappedBy property filled. Owning side related table has foreign key to the inverse related table.

FetchType

When ever one has an association there is a question of FetchType value. Two options there are to be picked from EAGER or LAZY. Difference is only that if EAGER option is selected data is loaded right away and if LAZY option is selected data is loaded after the request. This difference can be used into your advantage depending of how you use the data. It is important to note that eager option takes more time to execute, since it is bigger sql query right?

Lets see traverse problem:

If we have LAZY option selected every time getDepartments method is called database will be pinged for new data, this can be very slow in case of many companies.

If we have EAGER option, what if we have company with 10000 departments, do we really need to load all of them every time? Or we can get company first and then filter through the departments …

EAGER vs LAZY depends of the problem that is supposed to be solved, so think first and code after is the mantra here.

 

ForeignKey

@JoingColumn has many properties, few that are important are nullable and foreignKey.

Nullable property set to false tells JPA that Department must have the Company attached. This will translate into notNull column in the related sql table.
ForeignKey property specifies SQL foreign key details in this case its name, if this property is not filled JPA will find suitable name for your foreign key.

 

Spring Repository

There are two entities and two Spring repositories with CRUD methods. Additionally I have added findAll that returns the java.util.List.

Unit Tests

To demonstrate that all works as expected 3 tests are created

  1. Test Create Company with Departments in one save action.
  2. Test create Company and connect it with new Department, here i have two save actions one to create company and other to create department.
  3. Test Cascade deletion of Department, company is deleted and with it departmetns are deleted as well automatically.

Two lines here are most important :

Here both sides of the association are maintained and without it of course is will not work.

 

In above test I have created company with out any departments then new department is created and added to the company. Rest of the code just validates.

 

Cascade delete works as it is expected, when company is deleted all departments go with it.

In the next post I will talk about association ManyToMany using example Teacher Student. Here teacher can tech more then one student and student can be thought by more then one teacher.

 

JPA – Associations @OneToOne , @OneToMany, @ManyToOne, @ManyToMany part 1

JPA entities are usually related to other entities. There are in total 4 types of associations

  • @OneToOne association is used when one entity has only one other entity that it relates to. Example of this association is Employee and EmployeeDetail. Each employee has( or can have) only one detail.
  • @OneToMany, is used when entity is related to many entities. Example is Company that has many Departments.
  • @ManyToOne is opposite from previous association. In this case Department is related to one Company.
  • @ManyToMany, example of this association is a Teacher that can tech many students and Student that can be thought by many teachers.

@OneOnOne

To demonstrate this association I will use example where Employee has EmployeeDetail.

  • @Entity annotates this class as JPA entity
  • @Table specifies table name, in this case EMPLOYEE
  • Primary column as identity is specified using using @Id and @GeneratedValue
  • @Column specifies column name, length and is null among with other properties that can be specified.

In above entities there are two @OneToOne annotated properties to define both sides of the association, owning and inverse side.

Questions that we need to answer are:

  • Foreign key is going to be created in which table?
  • Who is the owner if the association?
  • If one entity is deleted is other entity going to be deleted as well?

Looking to above configuration foreign key is going to be created in table that is related to entity EmplyeeDetail. This is specified using  @JoinColumn(name = EMPLOYEE_ID_) , name also specifies the name of the column in the database table.

Owner of association is EmployeeDetail entity. Not owning( or inverse) side must have mappedBy attribute in its OneToOne annotation.

When Employee is deleted EmployeeDetail should be deleted as well. This is specified by cascade being located in Employee entity.

UnitTests

To make sure this works I have created two JpaRepository interfaces that are used.

CrudRepository interface has CRUD methods that are going to be used in unit test.

What is important to note is when creating Employee and EmployeeDetail both sides of association  must be maintained.

Cascade Delete Test

First I will load both employee and employeeDetail from the database to prove that they both exist. Of course both entities are created in before method that you can see above.

Then I delete the employee and check did this delete employeeDetail as well.

Why was the EmployeeDetail deleted?

It is deleted because of cascade = CascadeType.ALL specified in Employee entity. It is important to thing before so that you do not automatically remove wrong entities.

 

JPA –Custom Validation Contraints

The Java Validation API contains numerous annotations used for validation as I have written before about it. Provided annotations can never cover all the cases  developer might need so in this tutorial I will cover the concept of creating custom annotations and validation constraints using JPA Entities.

I will create an example  that will validate entity property userName and insure that username holds only letters.

@UserName Validation Constraint

Creating validation constraint has two steps, first you must create annotation and then constrain validator.

Annotation must bi annotated with several other annotations.

@Target specifies what elements can be annotated, if missing then all elements can be annotated with in this case @UserName annotation. Possible values are from docs

  • ElementType.TYPE, Class, interface (including annotation type), or enum declaration
  • ElementType.FIELD, Field declaration (includes enum constants)
  • ElementType.METHOD, Method declaration
  • ElementType.PARAMETER, Formal parameter declaration
  • ElementType.CONSTRUCTOR, Constructor declaration
  • ElementType.LOCAL_VARIABLE, Local variable declaration
  • ElementType.ANNOTATION_TYPE, Annotation type declaration
  • ElementType.PACKAGE, Package declaration
  • ElementType.TYPE_PARAMETER, Type parameter declaration (@since 1.8)
  • ElementType.TYPE_USE, Use of a type @since 1.8

@Retention, defines how long annotations are supposed to be retained. There ares several retention policies

  • SOURCE, annotations are used only in source and are discarded after compilation
  • CLASS, annotations are discarted on class load and are usefull for bytecode-level post processing . This is default option.
  • RUNTIME, annotations survive compilations and class loading and of course are available for reflection at runtime. Of course I pick this value because validation is done in runtime when validation is being invoked.

@Constraint, belongs to Java Validation API and helps specify class that is used to validate the value( like userName).

Groups and payload are required by validation api and message is mandatory.

UserNameValidator

ConstrainValidator implementsConstraintValidator that has two methods initialize and isValid and also two type parameters annotation and value that is to be validated. It does not do much it just checks if username consists of all letters :).

How to use custom validation constraint for your Entity?

Here is the part of Entity called User

What happens when someone tries to create entity with wrong value?

Exception ConstraintViolationException is thrown with specified message

 

Is it easy to create your own constraint that will be applied on type User

  1. Create annotation with @Target=ElementType.TYPE
  2. @Constraint(validatedBy = YourOwnValidator.class)
  3. YourOwnValidator implements ConstraintValidator<YourOwnAnnotation,User>

Happy coding.

JPA – Validation Contraints

JPA comes with few default constraints that help validate entity properties.

@Null and @NotNull

Force property to be null or !null.

Accepts any type.

@AssertFalse and @AssertTrue

Force value of the property to false or true.

Accepts Boolean type.

@DecimalMax, @DecimalMin and @Digits

Decimal min and max force the property to be in the specified range. Digits forces the property to be of the specified format.

Accepts BigDecimal, BigInteger, CharSequence, byte, short, int, long with their respective wrappers

@Past and @Future

Force property to be in the correct time frame.

Accepts  java.util.Date and java.util.Calendar types.

note: null is considered valid

@Min, @Max

Force the property value to be in the correct number range.

Accepts BigDecimal, BigInteger, byte, short, int, long, with their respective wrappers

@Pattern

Forces the property value to be of specified pattern.

Accepts CharSequence type.

@Size

Forces the property value to be in the specified length range.

Accepts types of

  • CharSequence (length of character sequence is evaluated)
  • Collection (collection size is evaluated)
  • Map (map size is evaluated)
  • Array (array length is evaluated)

 

JPA tutorial – Inheritance strategy

JPA supports 3 inheritance strategies

  • SINGLE_TABLE
  • TABLE_PER_CLASS
  • JOINED

For demonstration I will try to solve the problem of document management system where I need to store different types of documents, letter and invoice document. Here is the class diagram.

 

Document Class Diagram

Document Class Diagram

Single table strategy

For single table strategy JPA will create one table that has columns from all entities from the inheritance tree.

Create table SQL:

Observe the DOCUMENT_TYPE column, this is the discriminator column used by JPA to distinguish document types.

Entities

Code for all classes involved

Abstract Document Entity

 

@MappedSuperClass marks non entity super class.

Document Entity

 

In the DocumentEntity I have specified that

  • This is an entity
  • Inheritance is SINGLE_TABLE
  • Entity should be  mapped to table named DOCUMENT
  • Discriminator column is named DOCUMENT_TYPE
Invoice Document Entity

Invoice Document entity extends the Document Entity and important part is the annotation DiscriminatorValue. I will get to get in a bit.

Letter Document Entity

Letter Entity is similar to the Invoice Entity

Spring Repository and Unit Test

I will use spring repository to have CRUD support and write a unit test that will demonstrate insert and select all functionalities.

After this test is executed next SQL queries are used.

Creating entities SQL

Observe the INV and LET values, this are the values from the discriminator value specified above.

Select SQL

This is the simple select all query.

Joined strategy

To demonstrate joined strategy few changes must be done in the entities annotations. Unchanged parts are not shown in the listings.

Here is the list of changes

  • @Inheritance strategy is changed to InheritanceType.JOINED
  • @DiscriminatorColumn is removed since it does not have any effect in hibernate
  • @DiscriminatorValue is removed from Invoice and Letter
  • @Table is added

In the MySQL has 3 tables now, here is the diagram

MySQL table diagram

MySQL table diagram

Creating entities SQL

Select SQL

Select is not totally different with two left outer joins

 

I hope that this tutorial will help you to decide what inheritance strategy should you choose.

JPA Tutorial – @ElementCollection with basic types and embeddable

When entity has collection of basic types @ElementCollection must be used.

@ElementCollection with Basic Type

We have Pomodoro entity that has collection of tags.

Pomodoro Entity

Two tables will be created for this case PM_POMODORO  and PM_POMODORO_TAGS  tables. Here is the create SQL :

Observe the foreign key POMODORO_ID_  in PM_POMODORO_TAGS  table that is properly named as it is specified by @CollectionTable .

@JoinColumn has additional properties that you can use

  •  unique ( default is false) , defines uniquness
  • nullable (default is true), defines nullability
  • insertable and updatable, defines whether this column should be used in insert and update statements.
  • columnDefinition, defines SQL fragment that is used for generation of DDL for column. Here is one example of the value  VARCHAR(32) .

@ElementCollection with Embeddable

What if Tag is not a simple string but a Embeddable entity with two properties, name and the color? We will add TagEntity and annotate it with @Embeddable

Pomodoro entity is changed a bit

POMODORO_TAG table create SQL

@ElementCollection with java.util.Map

Element collection can be used with Map as well, for this we can use basic example of the Contact that has multiple phone numbers. For example home, work and other number.

Here we need to specify multiple annotations

  • @ElementCollection to specify fetch type
  • @Column, to specify name of the column that will hold the phone number
  • @CollectionTable, to specify the name of the table
  • @MapKeyColumn to specify the key column name( key is the phone type)

Lets check the PHONES table create SQL

Problem with upper example is that we have limited number of relationships( phone types in this case) so we should be using enumeration. Here is how to do this.

@MapKeyEnumerated annotation is used to specify how the PHONE_TYPE will be saved into the database, as

  • ordinal (0, 1, 2)
  • name (HOME,WORK,OTHER)

JPA Tutorial – Entities and primary keys

Introduction

Entity is the lightweight domain object, usually instance of this entity represents one row in the database and its properties represent one table column. It is important to know how to map property of the class to the column of the database table. In this tutorial I am going to show you the details that you can use in your own projects.

Entity

Declaring the entity is done using JPA annotation @Entity, this annotation can be combined with other annotations like @Table.

In this example above we have declared one entity named Pomodoro that is saved into table with specified name PM_POMODORO .

Unique indexes can be also added by setting UniqueConstraint  like in the above example.

Primary keys

Every entity should have primary key, additionally primary key should be taken into account in equals and toHash methods.

Declaring property of the class to be primary key is done using annotation @Id . When no additional annotations are used then application must specify primary key value. Primary key can also be auto generated by specifying @GeneratedValue with desired strategy.

Primary key generation strategies can be :

  • AUTO (default) this is default option. Depending of the database server it can be identity or sequence. Default option for MySQL, SQLite and MsSQL is IDENTITY and SEQUENCE for Oracle and PostgreSQL
  • IDENTITY, is similar to AUTO. Next value is generated and it is increased by 1.
  • SEQUENCE
  • TABLE

Sequence primary key generation strategy can be specified using next example

Now instead of using identity custom sequence generation is used that is in this case incremented by 3.

Table primary key generation is similar to sequence strategy, but sequence is simulated using table.

 

Composite primary keys

Primary keys can be composite and be consisted of two or more columns. Here is an example where we have two properties annotated with @Id.

Another way of specifying composite primary key is by using @EmbedableId and @Embedable. Here is how to do this:

You can notice that I have replaced properties id and projectId with property of type CompositeId. Here is the implementation of this class. What is important is that it implements Serialisable interface and is annotated with @Embeddable.

 

JPA supports numberous types for primary key property, here is a list of java types that can be used for primary keys.

  • Java primitive types
  • Java primitive wrapper types
  • java.lang.String
  • java.util.Date (the temporal type should be DATE)
  • java.sql.Date
  • java.math.BigDecimal
  • java.math.BigInteger

Additionally primary key type should not be of any floating-point type.

 

This is is what relates to primary keys in JPA, stay tuned for other JPA related posts.