Kohei Nozaki's blog 

Just try to use ElementCollection with Set


Posted on Monday Feb 17, 2014 at 04:25PM in Technology


Just some notes about how it works, how create schemas, and how DMLs executes, and try to find its pros and cons.

Environment

  • WildFly 8.0.0.Final
  • Hibernate 4.3.1
  • PostgreSQL 9.2.4
  • postgresql-9.3-1100.jdbc41.jar

Example project

Whole project resources are available in GitHub.

Set<Basic>

Schema

jpatest=# \d setbasic
   Table "public.setbasic"
 Column |  Type  | Modifiers 
--------+--------+-----------
 id     | bigint | not null
Indexes:
    "setbasic_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "setbasic_set" CONSTRAINT "fk_qov1oy3cmf1wmttooahy264eh" FOREIGN KEY (setbasic_id) REFERENCES setbasic(id)

jpatest=# \d setbasic_set
           Table "public.setbasic_set"
   Column    |          Type          | Modifiers 
-------------+------------------------+-----------
 setbasic_id | bigint                 | not null
 set         | character varying(255) | 
Foreign-key constraints:
    "fk_qov1oy3cmf1wmttooahy264eh" FOREIGN KEY (setbasic_id) REFERENCES setbasic(id)

jpatest=# 

Entry data

log

13:59:11,377 DEBUG [org.hibernate.SQL] (default task-15) insert into SetBasic (id) values (?)
13:59:11,378 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
13:59:11,379 DEBUG [org.hibernate.SQL] (default task-15) insert into SetBasic_set (SetBasic_id, set) values (?, ?)
13:59:11,379 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
13:59:11,379 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [2] as [VARCHAR] - [hige]
13:59:11,380 DEBUG [org.hibernate.SQL] (default task-15) insert into SetBasic_set (SetBasic_id, set) values (?, ?)
13:59:11,380 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
13:59:11,380 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [2] as [VARCHAR] - [hoge]
13:59:11,381 DEBUG [org.hibernate.SQL] (default task-15) insert into SetBasic_set (SetBasic_id, set) values (?, ?)
13:59:11,381 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
13:59:11,381 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [2] as [VARCHAR] - [fuge]

table

jpatest=# select * from setbasic;
 id 
----
  1
(1 row)

jpatest=# select * from setbasic_set;
 setbasic_id | set  
-------------+------
           1 | hige
           1 | hoge
           1 | fuge
(3 rows)

jpatest=# 

Find

14:01:27,838 DEBUG [org.hibernate.SQL] (default task-8) select setbasic0_.id as id1_2_0_ from SetBasic setbasic0_ where setbasic0_.id=?
14:01:27,838 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-8) binding parameter [1] as [BIGINT] - [1]
14:01:27,839 DEBUG [org.hibernate.SQL] (default task-8) select set0_.SetBasic_id as SetBasic1_2_0_, set0_.set as set2_3_0_ from SetBasic_set set0_ where set0_.SetBasic_id=?
14:01:27,840 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-8) binding parameter [1] as [BIGINT] - [1]
14:01:27,839 FINE  [org.nailedtothex.jpatest.set.SetBasicTestDataManipulator] (default task-8) find(): [hige, hoge, fuge]

Add

log

14:03:45,339 DEBUG [org.hibernate.SQL] (default task-15) select setbasic0_.id as id1_2_0_ from SetBasic setbasic0_ where setbasic0_.id=?
14:03:45,340 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
14:03:45,341 DEBUG [org.hibernate.SQL] (default task-15) select set0_.SetBasic_id as SetBasic1_2_0_, set0_.set as set2_3_0_ from SetBasic_set set0_ where set0_.SetBasic_id=?
14:03:45,341 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
14:03:45,345 DEBUG [org.hibernate.SQL] (default task-15) insert into SetBasic_set (SetBasic_id, set) values (?, ?)
14:03:45,345 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [1] as [BIGINT] - [1]
14:03:45,345 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-15) binding parameter [2] as [VARCHAR] - [hege]

table

jpatest=# select * from setbasic_set;
 setbasic_id | set  
-------------+------
           1 | hoge
           1 | hige
           1 | fuge
           1 | hege
(4 rows)

jpatest=# 

Remove

log

14:05:08,367 DEBUG [org.hibernate.SQL] (default task-5) select setbasic0_.id as id1_2_0_ from SetBasic setbasic0_ where setbasic0_.id=?
14:05:08,368 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-5) binding parameter [1] as [BIGINT] - [1]
14:05:08,369 DEBUG [org.hibernate.SQL] (default task-5) select set0_.SetBasic_id as SetBasic1_2_0_, set0_.set as set2_3_0_ from SetBasic_set set0_ where set0_.SetBasic_id=?
14:05:08,369 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-5) binding parameter [1] as [BIGINT] - [1]
14:05:08,374 DEBUG [org.hibernate.SQL] (default task-5) delete from SetBasic_set where SetBasic_id=? and set=?
14:05:08,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-5) binding parameter [1] as [BIGINT] - [1]
14:05:08,374 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-5) binding parameter [2] as [VARCHAR] - [hige]

table

jpatest=# select * from setbasic_set;
 setbasic_id | set  
-------------+------
           1 | hoge
           1 | fuge
(2 rows)

jpatest=# 

Set<Embeddable>

Schema

jpatest=# \d setembeddableparent
Table "public.setembeddableparent"
 Column |  Type  | Modifiers 
--------+--------+-----------
 id     | bigint | not null
Indexes:
    "setembeddableparent_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "setembeddableparent_setembeddablechilds" CONSTRAINT "fk_r8ikgl74hjndujhjwuvnkt59m" FOREIGN KEY (setembeddableparent_id) REFERENCES setembeddableparent(id)

jpatest=# \d setembeddableparent_setembeddablechilds 
   Table "public.setembeddableparent_setembeddablechilds"
         Column         |          Type          | Modifiers 
------------------------+------------------------+-----------
 setembeddableparent_id | bigint                 | not null
 embfield1              | character varying(255) | 
 embfield2              | character varying(255) | 
Foreign-key constraints:
    "fk_r8ikgl74hjndujhjwuvnkt59m" FOREIGN KEY (setembeddableparent_id) REFERENCES setembeddableparent(id)

jpatest=# 

Entry data

log

14:06:58,199 DEBUG [org.hibernate.SQL] (default task-12) insert into SetEmbeddableParent (id) values (?)
14:06:58,199 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [1] as [BIGINT] - [1]
14:06:58,200 DEBUG [org.hibernate.SQL] (default task-12) insert into SetEmbeddableParent_setEmbeddableChilds (SetEmbeddableParent_id, embField1, embField2) values (?, ?, ?)
14:06:58,200 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [1] as [BIGINT] - [1]
14:06:58,200 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [2] as [VARCHAR] - [child3field1]
14:06:58,201 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [3] as [VARCHAR] - [child3field2]
14:06:58,201 DEBUG [org.hibernate.SQL] (default task-12) insert into SetEmbeddableParent_setEmbeddableChilds (SetEmbeddableParent_id, embField1, embField2) values (?, ?, ?)
14:06:58,202 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [1] as [BIGINT] - [1]
14:06:58,202 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [2] as [VARCHAR] - [child2field1]
14:06:58,202 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [3] as [VARCHAR] - [child2field2]
14:06:58,202 DEBUG [org.hibernate.SQL] (default task-12) insert into SetEmbeddableParent_setEmbeddableChilds (SetEmbeddableParent_id, embField1, embField2) values (?, ?, ?)
14:06:58,202 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [1] as [BIGINT] - [1]
14:06:58,203 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [2] as [VARCHAR] - [child1field1]
14:06:58,203 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-12) binding parameter [3] as [VARCHAR] - [child1field2]

table

jpatest=# select * from setembeddableparent;
 id 
----
  1
(1 row)

jpatest=# select * from setembeddableparent_setembeddablechilds;
 setembeddableparent_id |  embfield1   |  embfield2   
------------------------+--------------+--------------
                      1 | child3field1 | child3field2
                      1 | child2field1 | child2field2
                      1 | child1field1 | child1field2
(3 rows)

jpatest=# 

Find

14:10:32,579 DEBUG [org.hibernate.SQL] (default task-6) select setembedda0_.id as id1_4_0_ from SetEmbeddableParent setembedda0_ where setembedda0_.id=?
14:10:32,579 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-6) binding parameter [1] as [BIGINT] - [1]
14:10:32,580 DEBUG [org.hibernate.SQL] (default task-6) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_4_0_, setembedda0_.embField1 as embField2_5_0_, setembedda0_.embField2 as embField3_5_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
14:10:32,581 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-6) binding parameter [1] as [BIGINT] - [1]
14:10:32,580 FINE  [org.nailedtothex.jpatest.set.SetEmbeddableTestDataManipulator] (default task-6) [SetEmbeddableChild [embField1=child3field1, embField2=child3field2], SetEmbeddableChild [embField1=child2field1, embField2=child2field2], SetEmbeddableChild [embField1=child1field1, embField2=child1field2]]

Add

log

14:12:20,219 DEBUG [org.hibernate.SQL] (default task-13) select setembedda0_.id as id1_4_0_ from SetEmbeddableParent setembedda0_ where setembedda0_.id=?
14:12:20,220 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-13) binding parameter [1] as [BIGINT] - [1]
14:12:20,221 DEBUG [org.hibernate.SQL] (default task-13) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_4_0_, setembedda0_.embField1 as embField2_5_0_, setembedda0_.embField2 as embField3_5_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
14:12:20,221 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-13) binding parameter [1] as [BIGINT] - [1]
14:12:20,225 DEBUG [org.hibernate.SQL] (default task-13) insert into SetEmbeddableParent_setEmbeddableChilds (SetEmbeddableParent_id, embField1, embField2) values (?, ?, ?)
14:12:20,225 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-13) binding parameter [1] as [BIGINT] - [1]
14:12:20,225 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-13) binding parameter [2] as [VARCHAR] - [child4field1]
14:12:20,225 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-13) binding parameter [3] as [VARCHAR] - [child4field2]

table

jpatest=# select * from setembeddableparent_setembeddablechilds;
 setembeddableparent_id |  embfield1   |  embfield2   
------------------------+--------------+--------------
                      1 | child1field1 | child1field2
                      1 | child2field1 | child2field2
                      1 | child3field1 | child3field2
                      1 | child4field1 | child4field2
(4 rows)

Remove

log

14:14:48,499 DEBUG [org.hibernate.SQL] (default task-9) select setembedda0_.id as id1_4_0_ from SetEmbeddableParent setembedda0_ where setembedda0_.id=?
14:14:48,499 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-9) binding parameter [1] as [BIGINT] - [1]
14:14:48,500 DEBUG [org.hibernate.SQL] (default task-9) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_4_0_, setembedda0_.embField1 as embField2_5_0_, setembedda0_.embField2 as embField3_5_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
14:14:48,500 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-9) binding parameter [1] as [BIGINT] - [1]
14:14:48,500 FINE  [org.nailedtothex.jpatest.set.SetEmbeddableTestDataManipulator] (default task-9) [SetEmbeddableChild [embField1=child3field1, embField2=child3field2], SetEmbeddableChild [embField1=child2field1, embField2=child2field2], SetEmbeddableChild [embField1=child1field1, embField2=child1field2]]
14:14:48,505 DEBUG [org.hibernate.SQL] (default task-9) delete from SetEmbeddableParent_setEmbeddableChilds where SetEmbeddableParent_id=? and embField1=? and embField2=?
14:14:48,505 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-9) binding parameter [1] as [BIGINT] - [1]
14:14:48,505 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-9) binding parameter [2] as [VARCHAR] - [child1field1]
14:14:48,506 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-9) binding parameter [3] as [VARCHAR] - [child1field2]

table

jpatest=# select * from setembeddableparent_setembeddablechilds;
 setembeddableparent_id |  embfield1   |  embfield2   
------------------------+--------------+--------------
                      1 | child2field1 | child2field2
                      1 | child3field1 | child3field2
(2 rows)

jpatest=# 

Update

log

15:07:27,811 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [1] as [BIGINT] - [1]
15:07:27,812 DEBUG [org.hibernate.SQL] (default task-7) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_2_0_, setembedda0_.embField1 as embField2_3_0_, setembedda0_.embField2 as embField3_3_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
15:07:27,812 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [1] as [BIGINT] - [1]
15:07:27,815 DEBUG [org.hibernate.SQL] (default task-7) delete from SetEmbeddableParent_setEmbeddableChilds where SetEmbeddableParent_id=? and embField1=? and embField2=?
15:07:27,815 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [1] as [BIGINT] - [1]
15:07:27,815 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [2] as [VARCHAR] - [child2field1]
15:07:27,815 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [3] as [VARCHAR] - [child2field2]
15:07:27,816 DEBUG [org.hibernate.SQL] (default task-7) insert into SetEmbeddableParent_setEmbeddableChilds (SetEmbeddableParent_id, embField1, embField2) values (?, ?, ?)
15:07:27,816 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [1] as [BIGINT] - [1]
15:07:27,816 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [2] as [VARCHAR] - [child2field1]
15:07:27,816 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-7) binding parameter [3] as [VARCHAR] - [child2field2-updated]

table

jpatest=# select * from setembeddableparent_setembeddablechilds order by embfield1;
 setembeddableparent_id |  embfield1   |      embfield2       
------------------------+--------------+----------------------
                      1 | child1field1 | child1field2
                      1 | child2field1 | child2field2-updated
                      1 | child3field1 | child3field2
(3 rows)

jpatest=# 

Add a duplicate element

14:13:59,763 DEBUG [org.hibernate.SQL] (default task-14) select setembedda0_.id as id1_4_0_ from SetEmbeddableParent setembedda0_ where setembedda0_.id=?
14:13:59,764 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-14) binding parameter [1] as [BIGINT] - [1]
14:13:59,765 DEBUG [org.hibernate.SQL] (default task-14) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_4_0_, setembedda0_.embField1 as embField2_5_0_, setembedda0_.embField2 as embField3_5_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
14:13:59,765 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-14) binding parameter [1] as [BIGINT] - [1]
  • No changes are made to DB.

Remove a element that not exist

14:16:48,827 DEBUG [org.hibernate.SQL] (default task-10) select setembedda0_.id as id1_4_0_ from SetEmbeddableParent setembedda0_ where setembedda0_.id=?
14:16:48,828 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-10) binding parameter [1] as [BIGINT] - [1]
14:16:48,829 DEBUG [org.hibernate.SQL] (default task-10) select setembedda0_.SetEmbeddableParent_id as SetEmbed1_4_0_, setembedda0_.embField1 as embField2_5_0_, setembedda0_.embField2 as embField3_5_0_ from SetEmbeddableParent_setEmbeddableChilds setembedda0_ where setembedda0_.SetEmbeddableParent_id=?
14:16:48,829 TRACE [org.hibernate.type.descriptor.sql.BasicBinder] (default task-10) binding parameter [1] as [BIGINT] - [1]
  • No changes are made to DB.

Nested collection is prohibited

  • It said @ElementCollection can be used with embeddable or basic type only.

Conclusion

Pros

  • It works well as expected for some operations of Set API. it prevents that add duplicated elements.
  • It can reduce some annoying codes.

Cons

  • All elements are need to being fetched for manipulate, so maybe it is not good for large sets.
  • Child elements are not entities, so use of some convenient operations is impossible.

Remarks

  • Maybe it's good for proto-typing.
  • But I'm not sure about whether it is appropriate for production systems especially high-traffic concurrent systems.
  • For appropriate size sets, maybe 2nd level cache would be great help for its performance.