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 –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 – 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.