List of collections

Well, you've seen how to map simple types. Now it's time to move on to more interesting questions - how to map collections of objects.

And we can have objects in 5 groups:

  • Array - an array of objects
  • List - list of objects
  • Set - set of objects
  • Map - a dictionary of objects
  • Collection - a collection of objects

And an example of a class with a collection field:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @magical-annotation
   public List messages;
}

So what is this magical annotation that will allow us to store not one field, but many values?

This annotation is called @ElementCollection . Example:

@Entity
@Table(name="user")
class User  {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   public List<String> messages;
}

It is written very simply, but it works non-trivially.

Auxiliary table

All fields of the Entity class that contain many elements and are marked with the @ElementCollection annotation are contained in the database in a special auxiliary table. Which, in fact, is logical.

This table can contain data in two forms:

  • Ordered (List, Map) contain three columns:
    • Key Column (Foreign Key) – reference to the ID of the parent object.
    • Index Column - position/index in the collection.
    • Element Column - value.
  • Unordered (Set) contains two columns:
    • Key Column (Foreign Key) – reference to the ID of the parent object.
    • Element Column - value.

You can also set the name of this table explicitly using an annotation:

@CollectionTable(name="table_name")

Example:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message")
   public List<String> messages;
}

Important! If the @CollectionTable annotation is not specified, then Hibernate will build the table name itself based on the class name and the field name: the User class and the fieldmessagesname the table "User_messages".

Collection Collection

But let's not leave the creation of the auxiliary table to Hibernate and create it ourselves. First we need to create a table with two columns:

CREATE TABLE user_message {
    user_id INT,
    message VARCHAR(255)
};

Note that this table does not have its own id-column. This is the main feature of auxiliary tables. You will get acquainted with other types of auxiliary tables a little later.

Now we need to map this table to our fieldmessagesin the User class . This will look like this:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message", joinColumns = @JoinColumn(name = "user_id"))
   @Column(name = "message")
   public Set<String> messages;
}

Here it is worth paying attention to two things.

First, the message column, specified with the @Column(name = "message") annotation , is in the user_message auxiliary table, not the user table.

Secondly, in the @JoinColumn(name = "user_id") annotation , we specified the name of the user_id column, which refers to the id of the user table. This is so that Hibernate knows how to combine them correctly.

Collection

If you want to store the ordered elements of a list or array in an auxiliary table, then you need a table with three columns:

CREATE TABLE user_message {
    user_id INT,
    index INT,
    message VARCHAR(255)
};

If you don't like the column name "index", or you can't change it, you can specify a different name during mapping. To do this, you need to use the @Index annotation .

Example:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message",
       	indexes = { @Index(columnList = "list_index") }
       	joinColumns = @JoinColumn(name = "user_id"))
   @Column(name = "message")
   public List<String> messages;
}

Map Collection

And finally, you want to store not just a collection, but a HashMap, and you need two columns in an auxiliary table for it:

CREATE TABLE user_message {
    user_id INT,
    key VARCHAR(255),
    message VARCHAR(255)
};

In order to specify a key for a Map, you need the @MapKeyColumn annotation .

Example:

@Entity
@Table(name="user")
class User {
   @Id
   @Column(name="id")
   public Integer id;

   @ElementCollection
   @CollectionTable(name="user_message", joinColumns = @JoinColumn(name = "user_id"))
   @MapKeyColumn(name = "key")
   @Column(name = "message")
   public Map<String, String> messages;
}

You can find more information in the official documentation .

undefined
1
Task
Module 4. Working with databases, level 13, lesson 0
Locked
Arrangement of annotations
task1301
undefined
1
Task
Module 4. Working with databases, level 13, lesson 0
Locked
Annotation Arrangement 2
task1302