UserGuide uses examples from existing test cases
This commit is contained in:
parent
2bda2515af
commit
97ba351c2a
|
@ -1,6 +1,6 @@
|
|||
[[associations]]
|
||||
=== Associations
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/jpa/test/userguide/associations
|
||||
|
||||
Associations describe how two or more entities form a relationship based on a database joining semantics.
|
||||
|
||||
|
@ -10,31 +10,33 @@ Associations describe how two or more entities form a relationship based on a da
|
|||
`@ManyToOne` is the most common association, having a direct equivalent in the relational database as well (e.g. foreign key),
|
||||
and so it establishes a relationship between a child entity and a parent.
|
||||
|
||||
[[associations-many-to-one-example]]
|
||||
.`@ManyToOne` association
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/ManyToOne.java[]
|
||||
include::{sourcedir}/ManyToOneTest.java[tags=associations-many-to-one-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/ManyToOne.sql[]
|
||||
include::{sourcedir}/associations-many-to-one-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Each entity has a lifecycle of its own. Once the `@ManyToOne` association is set, Hibernate will set the associated database foreign key column.
|
||||
|
||||
[[associations-many-to-one-lifecycle-example]]
|
||||
.`@ManyToOne` association lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/ManyToOneLifecycle.java[]
|
||||
include::{sourcedir}/ManyToOneTest.java[tags=associations-many-to-one-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/ManyToOneLifecycle.sql[]
|
||||
include::{sourcedir}/associations-many-to-one-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -50,16 +52,17 @@ If there is a `@ManyToOne` association on the child side, the `@OneToMany` assoc
|
|||
|
||||
When using a unidirectional `@OneToMany` association, Hibernate resorts to using a link table between the two joining entities.
|
||||
|
||||
[[associations-one-to-many-unidirectional-example]]
|
||||
.Unidirectional `@OneToMany` association
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToMany.java[]
|
||||
include::{sourcedir}/OneToManyUnidirectionalTest.java[tags=associations-one-to-many-unidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToMany.sql[]
|
||||
include::{sourcedir}/associations-one-to-many-unidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -69,16 +72,17 @@ The `@OneToMany` association is by definition a parent association, even if it's
|
|||
Only the parent side of an association makes sense to cascade its entity state transitions to children.
|
||||
====
|
||||
|
||||
[[associations-one-to-many-unidirectional-lifecycle-example]]
|
||||
.Cascading `@OneToMany` association
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToManyLifecycle.java[]
|
||||
include::{sourcedir}/OneToManyUnidirectionalTest.java[tags=associations-one-to-many-unidirectional-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToManyLifecycle.sql[]
|
||||
include::{sourcedir}/associations-one-to-many-unidirectional-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -101,16 +105,17 @@ Although the Domain Model exposes two sides to navigate this association, behind
|
|||
|
||||
Every bidirectional association must have one owning side only (the child side), the other one being referred to as the _inverse_ (or the `mappedBy`) side.
|
||||
|
||||
[[associations-one-to-many-bidirectional-example]]
|
||||
.`@OneToMany` association mappedBy the `@ManyToOne` side
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToMany.java[]
|
||||
include::{sourcedir}/OneToManyBidirectionalTest.java[tags=associations-one-to-many-bidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToMany.sql[]
|
||||
include::{sourcedir}/associations-one-to-many-bidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -123,16 +128,17 @@ The `addPhone()` and `removePhone()` are utilities methods that synchronize both
|
|||
Because the `Phone` class has a `@NaturalId` column (the phone number being unique),
|
||||
the `equals()` and the `hashCode()` can make use of this property, and so the `removePhone()` logic is reduced to the `remove()` Java `Collection` method.
|
||||
|
||||
[[associations-one-to-many-bidirectional-lifecycle-example]]
|
||||
.Bidirectional `@OneToMany` with an owner `@ManyToOne` side lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToManyLifecycle.java[]
|
||||
include::{sourcedir}/OneToManyBidirectionalTest.java[tags=associations-one-to-many-bidirectional-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToManyLifecycle.sql[]
|
||||
include::{sourcedir}/associations-one-to-many-bidirectional-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -151,16 +157,17 @@ A bidirectional association features a `mappedBy` `@OneToOne` parent side too.
|
|||
[[associations-one-to-one-unidirectional]]
|
||||
===== Unidirectional `@OneToOne`
|
||||
|
||||
[[associations-one-to-one-unidirectional-example]]
|
||||
.Unidirectional `@OneToOne`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToOne.java[]
|
||||
include::{sourcedir}/OneToOneUnidirectionalTest.java[tags=associations-one-to-one-unidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalOneToOne.sql[]
|
||||
include::{sourcedir}/associations-one-to-one-unidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -174,42 +181,46 @@ This mapping requires a bidirectional `@OneToOne` association as you can see in
|
|||
[[associations-one-to-one-bidirectional]]
|
||||
===== Bidirectional `@OneToOne`
|
||||
|
||||
[[associations-one-to-one-bidirectional-example]]
|
||||
.Bidirectional `@OneToOne`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToOne.java[]
|
||||
include::{sourcedir}/OneToOneBidirectionalTest.java[tags=associations-one-to-one-bidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToOne.sql[]
|
||||
include::{sourcedir}/associations-one-to-one-bidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
This time, the `PhoneDetails` owns the association, and, like any bidirectional association, the parent-side can propagate its lifecycle to the child-side through cascading.
|
||||
|
||||
[[associations-one-to-one-bidirectional-lifecycle-example]]
|
||||
.Bidirectional `@OneToOne` lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToOneLifecycle.java[]
|
||||
include::{sourcedir}/OneToOneBidirectionalTest.java[tags=associations-one-to-one-bidirectional-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToOneLifecycle.sql[]
|
||||
include::{sourcedir}/associations-one-to-one-bidirectional-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
When using a bidirectional `@OneToOne` association, Hibernate enforces the unique constraint upon fetching the child-side.
|
||||
If there are more than one children associated to the same parent, Hibernate will throw a constraint violation exception.
|
||||
Continuing the previous example, when adding another `PhoneDetails`, Hibernate validates the uniqueness constraint when reloading the `Phone` object.
|
||||
|
||||
[[associations-one-to-one-bidirectional-constraint-example]]
|
||||
.Bidirectional `@OneToOne` unique constraint
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalOneToOneConstraint.java[]
|
||||
include::{sourcedir}/OneToOneBidirectionalTest.java[tags=associations-one-to-one-bidirectional-constraint-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -222,16 +233,17 @@ Like the `@OneToMany` association, `@ManyToMany` can be a either unidirectional
|
|||
[[associations-many-to-many-unidirectional]]
|
||||
===== Unidirectional `@ManyToMany`
|
||||
|
||||
[[associations-many-to-many-unidirectional-example]]
|
||||
.Unidirectional `@ManyToMany`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToMany.java[]
|
||||
include::{sourcedir}/ManyToManyUnidirectionalTest.java[tags=associations-many-to-many-unidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToMany.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-unidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -240,16 +252,17 @@ Just like with unidirectional `@OneToMany` associations, the link table is contr
|
|||
When an entity is removed from the `@ManyToMany` collection, Hibernate simply deletes the joining record in the link table.
|
||||
Unfortunately, this operation requires removing all entries associated to a given parent and recreating the ones that are listed in the current running persistent context.
|
||||
|
||||
[[associations-many-to-many-unidirectional-lifecycle-example]]
|
||||
.Unidirectional `@ManyToMany` lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToManyLifecycle.java[]
|
||||
include::{sourcedir}/ManyToManyUnidirectionalTest.java[tags=associations-many-to-many-unidirectional-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToManyLifecycle.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-unidirectional-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -274,16 +287,17 @@ Caused by: java.sql.SQLIntegrityConstraintViolationException: integrity constrai
|
|||
|
||||
By simply removing the parent-side, Hibernate can safely remove the associated link records as you can see in the following example:
|
||||
|
||||
[[associations-many-to-many-unidirectional-remove-example]]
|
||||
.Unidirectional `@ManyToMany` entity removal
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToManyRemove.java[]
|
||||
include::{sourcedir}/ManyToManyUnidirectionalTest.java[tags=associations-many-to-many-unidirectional-remove-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/UnidirectionalManyToManyRemove.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-unidirectional-remove-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -293,31 +307,33 @@ include::{sourcedir}/associations/UnidirectionalManyToManyRemove.sql[]
|
|||
A bidirectional `@ManyToMany` association has an owning and a `mappedBy` side.
|
||||
To preserve synchronicity between both sides, it's good practice to provide helper methods for adding or removing child entities.
|
||||
|
||||
[[associations-many-to-many-bidirectional-example]]
|
||||
.Bidirectional `@ManyToMany`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToMany.java[]
|
||||
include::{sourcedir}/ManyToManyBidirectionalTest.java[tags=associations-many-to-many-bidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToMany.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-bidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
With the helper methods in place, the synchronicity management can be simplified, as you can see in the following example:
|
||||
|
||||
[[associations-many-to-many-bidirectional-lifecycle-example]]
|
||||
.Bidirectional `@ManyToMany` lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyLifecycle.java[]
|
||||
include::{sourcedir}/ManyToManyBidirectionalTest.java[tags=associations-many-to-many-bidirectional-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyLifecycle.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-bidirectional-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -331,16 +347,17 @@ To overcome this limitation, the the link table must be directly exposed and the
|
|||
To most natural `@ManyToMany` association follows the same logic employed by the database schema,
|
||||
and the link table has an associated entity which controls the relationship for both sides that need to be joined.
|
||||
|
||||
[[associations-many-to-many-bidirectional-with-link-entity-example]]
|
||||
.Bidirectional many-to-many with link entity
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyWithLinkEntity.java[]
|
||||
include::{sourcedir}/ManyToManyBidirectionalWithLinkEntityTest.java[tags=associations-many-to-many-bidirectional-with-link-entity-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyWithLinkEntity.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-bidirectional-with-link-entity-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -355,16 +372,17 @@ For more details, see the <<chapters/domain/identifiers.adoc#identifiers-composi
|
|||
|
||||
The entity state transitions are better managed than in the previous bidirectional `@ManyToMany` case.
|
||||
|
||||
[[associations-many-to-many-bidirectional-with-link-entity-lifecycle-example]]
|
||||
.Bidirectional many-to-many with link entity lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyWithLinkEntityLifecycle.java[]
|
||||
include::{sourcedir}/ManyToManyBidirectionalWithLinkEntityTest.java[tags=associations-many-to-many-bidirectional-with-link-entity-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/associations/BidirectionalManyToManyWithLinkEntityLifecycle.sql[]
|
||||
include::{sourcedir}/associations-many-to-many-bidirectional-with-link-entity-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[[collections]]
|
||||
=== Collections
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/jpa/test/userguide/collections
|
||||
|
||||
Naturally Hibernate also allows to persist collections.
|
||||
These persistent collections can contain almost any other Hibernate type, including: basic types, custom types, components and references to other entities.
|
||||
|
@ -22,11 +22,14 @@ The actual interface might be `java.util.Collection`, `java.util.List`, `java.ut
|
|||
|
||||
As the following example demonstrates, it's important to use the interface type and not the collection implementation, as declared in the entity mapping.
|
||||
|
||||
[[collections-collection-proxy-example]]
|
||||
.Hibernate uses its own collection implementations
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/CollectionProxy.java[]
|
||||
include::{sourcedir}/BasicTypeElementCollectionTest.java[tags=collections-collection-proxy-entity-example,indent=0]
|
||||
|
||||
include::{sourcedir}/BasicTypeElementCollectionTest.java[tags=collections-collection-proxy-usage-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -63,47 +66,52 @@ The lifecycle of the value-type collection is entirely controlled by its owning
|
|||
Considering the previous example mapping, when clearing the phone collection, Hibernate deletes all the associated phones.
|
||||
When adding a new element to the value type collection, Hibernate issues a new insert statement.
|
||||
|
||||
[[collections-value-type-collection-lifecycle-example]]
|
||||
.Value type collection lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionLifecycle.java[]
|
||||
include::{sourcedir}/BasicTypeElementCollectionTest.java[tags=collections-value-type-collection-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionLifecycle.sql[]
|
||||
include::{sourcedir}/collections-value-type-collection-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
If removing all elements or adding new ones is rather straightforward, removing a certain entry actually requires reconstructing the whole collection from scratch.
|
||||
|
||||
[[collections-value-type-collection-remove-example]]
|
||||
.Removing collection elements
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionLifecycleRemove.java[]
|
||||
include::{sourcedir}/BasicTypeElementCollectionTest.java[tags=collections-value-type-collection-remove-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionLifecycleRemove.sql[]
|
||||
include::{sourcedir}/collections-value-type-collection-remove-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Depending on the number of elements, this behavior might not be efficient, if many elements need to be deleted and reinserted back into the database table.
|
||||
A workaround is to use an `@OrderColumn`, which, although not as efficient as when using the actual link table primary key, might improve the efficiency of the remove operations.
|
||||
|
||||
[[collections-value-type-collection-order-column-remove-example]]
|
||||
.Removing collection elements using the order column
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionOrderColumnLifecycleRemove.java[]
|
||||
include::{sourcedir}/BasicTypeOrderColumnElementCollectionTest.java[tags=collections-value-type-collection-order-column-remove-entity-example,indent=0]
|
||||
|
||||
include::{sourcedir}/BasicTypeOrderColumnElementCollectionTest.java[tags=collections-value-type-collection-order-column-remove-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionOrderColumnLifecycleRemove.sql[]
|
||||
include::{sourcedir}/collections-value-type-collection-order-column-remove-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -116,16 +124,19 @@ Removing from the head or the middle of the collection requires deleting the ext
|
|||
Embeddable type collections behave the same way as value type collections.
|
||||
Adding embeddables to the collection triggers the associated insert statements and removing elements from the collection will generate delete statements.
|
||||
|
||||
[[collections-embeddable-type-collection-lifecycle-example]]
|
||||
.Embeddable type collections
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/EmbeddableElementCollectionLifecycle.java[]
|
||||
include::{sourcedir}/EmbeddableTypeElementCollectionTest.java[tags=collections-embeddable-type-collection-lifecycle-entity-example,indent=0]
|
||||
|
||||
include::{sourcedir}/EmbeddableTypeElementCollectionTest.java[tags=collections-embeddable-type-collection-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/EmbeddableElementCollectionLifecycle.sql[]
|
||||
include::{sourcedir}/collections-embeddable-type-collection-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -166,16 +177,17 @@ Bags are unordered lists and we can have unidirectional bags or bidirectional on
|
|||
The unidirectional bag is mapped using a single `@OneToMany` annotation on the parent side of the association.
|
||||
Behind the scenes, Hibernate requires an association table to manage the parent-child relationship, as we can see in the following example:
|
||||
|
||||
[[collections-unidirectional-bag-example]]
|
||||
.Unidirectional bag
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalBag.java[]
|
||||
include::{sourcedir}/UnidirectionalBagTest.java[tags=collections-unidirectional-bag-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalBag.sql[]
|
||||
include::{sourcedir}/collections-unidirectional-bag-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -187,16 +199,17 @@ Cascades can propagate an entity state transition from a parent entity to its ch
|
|||
|
||||
By marking the parent side with the `CascadeType.ALL` attribute, the unidirectional association lifecycle becomes very similar to that of a value type collection.
|
||||
|
||||
[[collections-unidirectional-bag-lifecycle-example]]
|
||||
.Unidirectional bag lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalBagLifecyclePersist.java[]
|
||||
include::{sourcedir}/UnidirectionalBagTest.java[tags=collections-unidirectional-bag-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalBagLifecyclePersist.sql[]
|
||||
include::{sourcedir}/collections-unidirectional-bag-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -214,37 +227,45 @@ Because the parent-side cannot uniquely identify each individual child, Hibernat
|
|||
The bidirectional bag is the most common type of entity collection.
|
||||
The `@ManyToOne` side is the owning side of the bidirectional bag association, while the `@OneToMany` is the _inverse_ side, being marked with the `mappedBy` attribute.
|
||||
|
||||
[[collections-bidirectional-bag-example]]
|
||||
.Bidirectional bag
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalBag.java[]
|
||||
include::{sourcedir}/BidirectionalBagTest.java[tags=collections-bidirectional-bag-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalBag.sql[]
|
||||
include::{sourcedir}/collections-bidirectional-bag-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[collections-bidirectional-bag-lifecycle-example]]
|
||||
.Bidirectional bag lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalBagLifecycle.java[]
|
||||
include::{sourcedir}/BidirectionalBagTest.java[tags=collections-bidirectional-bag-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalBagLifecycle.sql[]
|
||||
include::{sourcedir}/collections-bidirectional-bag-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[collections-bidirectional-bag-orphan-removal-example]]
|
||||
.Bidirectional bag with orphan removal
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalBagOrphanRemoval.java[]
|
||||
include::{sourcedir}/BidirectionalBagOrphanRemovalTest.java[tags=collections-bidirectional-bag-orphan-removal-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections-bidirectional-bag-orphan-removal-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -264,22 +285,24 @@ To preserve the collection element order, there are two possibilities:
|
|||
|
||||
When using the `@OrderBy` annotation, the mapping looks as follows:
|
||||
|
||||
[[collections-unidirectional-ordered-list-order-by-example]]
|
||||
.Unidirectional `@OrderBy` list
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalOrderByList.java[]
|
||||
include::{sourcedir}/UnidirectionalOrderedByListTest.java[tags=collections-unidirectional-ordered-list-order-by-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
The database mapping is the same as with the <<collections-unidirectional-bag>> example, so it won't be repeated.
|
||||
Upon fetching the collection, Hibernate generates the following select statement:
|
||||
|
||||
[[collections-unidirectional-ordered-list-order-by-select-example]]
|
||||
.Unidirectional `@OrderBy` list select statement
|
||||
====
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalOrderByListSelect.sql[]
|
||||
include::{sourcedir}/collections-unidirectional-ordered-list-order-by-select-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -294,27 +317,29 @@ If no property is specified (e.g. `@OrderBy`), the primary key of the child enti
|
|||
|
||||
Another ordering option is to use the `@OrderColumn` annotation:
|
||||
|
||||
[[collections-unidirectional-ordered-list-order-column-example]]
|
||||
.Unidirectional `@OrderColumn` list
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalOrderColumnList.java[]
|
||||
include::{sourcedir}/UnidirectionalOrderColumnListTest.java[tags=collections-unidirectional-ordered-list-order-column-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalOrderColumnList.sql[]
|
||||
include::{sourcedir}/collections-unidirectional-ordered-list-order-column-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
This time, the link table takes the `order_id` column and uses it to materialize the collection element order.
|
||||
When fetching the list, the following select query is executed:
|
||||
|
||||
[[collections-unidirectional-ordered-list-order-column-select-example]]
|
||||
.Unidirectional `@OrderColumn` list select statement
|
||||
====
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalOrderColumnListSelect.sql[]
|
||||
include::{sourcedir}/collections-unidirectional-ordered-list-order-column-select-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -325,11 +350,12 @@ With the `order_id` column in place, Hibernate can order the list in-memory afte
|
|||
|
||||
The mapping is similar with the <<collections-bidirectional-bag>> example, just that the parent side is going to be annotated with either `@OrderBy` or `@OrderColumn`.
|
||||
|
||||
[[collections-bidirectional-ordered-list-order-by-example]]
|
||||
.Bidirectional `@OrderBy` list
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalOrderByList.java[]
|
||||
include::{sourcedir}/BidirectionalOrderByListTest.java[tags=collections-bidirectional-ordered-list-order-by-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -337,16 +363,17 @@ Just like with the unidirectional `@OrderBy` list, the `number` column is used t
|
|||
|
||||
When using the `@OrderColumn` annotation, the `order_id` column is going to be embedded in the child table:
|
||||
|
||||
[[collections-bidirectional-ordered-list-order-column-example]]
|
||||
.Bidirectional `@OrderColumn` list
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalOrderColumnList.java[]
|
||||
include::{sourcedir}/BidirectionalOrderColumnListTest.java[tags=collections-bidirectional-ordered-list-order-column-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalOrderColumnList.sql[]
|
||||
include::{sourcedir}/collections-bidirectional-ordered-list-order-column-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -362,11 +389,12 @@ Sets are collections that don't allow duplicate entries and Hibernate supports b
|
|||
|
||||
The unidirectional set uses a link table to hold the parent-child associations and the entity mapping looks as follows:
|
||||
|
||||
[[collections-unidirectional-set-example]]
|
||||
.Unidirectional set
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalSet.java[]
|
||||
include::{sourcedir}/UnidirectionalSetTest.java[tags=collections-unidirectional-set-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -385,11 +413,12 @@ In the absence of a custom equals/hashCode implementation logic, Hibernate will
|
|||
Just like bidirectional bags, the bidirectional set doesn't use a link table, and the child table has a foreign key referencing the parent table primary key.
|
||||
The lifecycle is just like with bidirectional bags except for the duplicates which are filtered out.
|
||||
|
||||
[[collections-bidirectional-set-example]]
|
||||
.Bidirectional set
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalSet.java[]
|
||||
include::{sourcedir}/BidirectionalSetTest.java[tags=collections-bidirectional-set-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -404,11 +433,12 @@ According to the `SortedSet` contract, all elements must implement the comparabl
|
|||
|
||||
A `SortedSet` that relies on the natural sorting order given by the child element `Comparable` implementation logic must be annotated with the `@SortNatural` Hibernate annotation.
|
||||
|
||||
[[collections-unidirectional-sorted-set-natural-comparator-example]]
|
||||
.Unidirectional natural sorted set
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalNaturalSortedSet.java[]
|
||||
include::{sourcedir}/UnidirectionalSortedSetTest.java[tags=collections-unidirectional-sorted-set-natural-comparator-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -416,11 +446,12 @@ The lifecycle and the database mapping are identical to the <<collections-unidir
|
|||
|
||||
To provide a custom sorting logic, Hibernate also provides a `@SortComparator` annotation:
|
||||
|
||||
[[collections-unidirectional-sorted-set-custom-comparator-example]]
|
||||
.Unidirectional custom comparator sorted set
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalCustomSortedSet.java[]
|
||||
include::{sourcedir}/UnidirectionalComparatorSortedSetTest.java[tags=collections-unidirectional-sorted-set-custom-comparator-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -429,11 +460,14 @@ include::{sourcedir}/collections/UnidirectionalCustomSortedSet.java[]
|
|||
|
||||
The `@SortNatural` and `@SortComparator` work the same for bidirectional sorted sets too:
|
||||
|
||||
[[collections-bidirectional-sorted-set-example]]
|
||||
.Bidirectional natural sorted set
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalSortedSet.java[]
|
||||
include::{sourcedir}/BidirectionalSortedSetTest.java[tags=collections-bidirectional-sorted-set-example,indent=0]
|
||||
|
||||
include::{sourcedir}/UnidirectionalComparatorSortedSetTest.java[lines=75..77,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -455,31 +489,33 @@ Hibernate allows using the following map keys:
|
|||
|
||||
A map of value type must use the `@ElementCollection` annotation, just like value type lists, bags or sets.
|
||||
|
||||
[[collections-map-value-type-entity-key-example]]
|
||||
.Value type map with an entity as a map key
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionMap.java[]
|
||||
include::{sourcedir}/ElementCollectionMapTest.java[tags=collections-map-value-type-entity-key-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionMap.sql[]
|
||||
include::{sourcedir}/collections-map-value-type-entity-key-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Adding entries to the map generates the following SQL statements:
|
||||
|
||||
[[collections-map-value-type-entity-key-add-example]]
|
||||
.Adding value type map entries
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionMapPersist.java[]
|
||||
include::{sourcedir}/ElementCollectionMapTest.java[tags=collections-map-value-type-entity-key-add-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/ElementCollectionMapPersist.sql[]
|
||||
include::{sourcedir}/collections-map-value-type-entity-key-add-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -490,16 +526,17 @@ A unidirectional map exposes a parent-child association from the parent-side onl
|
|||
The following example shows a unidirectional map which also uses a `@MapKeyTemporal` annotation.
|
||||
The map key is a timestamp and it's taken from the child entity table.
|
||||
|
||||
[[collections-map-unidirectional-example]]
|
||||
.Unidirectional Map
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalMap.java[]
|
||||
include::{sourcedir}/UnidirectionalMapTest.java[tags=collections-map-unidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/UnidirectionalMap.sql[]
|
||||
include::{sourcedir}/collections-map-unidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -509,16 +546,17 @@ include::{sourcedir}/collections/UnidirectionalMap.sql[]
|
|||
Like most bidirectional associations, this relationship is owned by the child-side while the parent is the inverse side abd can propagate its own state transitions to the child entities.
|
||||
In the following example, you can see that `@MapKeyEnumerated` was used so that the `Phone` enumeration becomes the map key.
|
||||
|
||||
[[collections-map-bidirectional-example]]
|
||||
.Bidirectional Map
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalMap.java[]
|
||||
include::{sourcedir}/BidirectionalMapTest.java[tags=collections-map-bidirectional-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/BidirectionalMap.sql[]
|
||||
include::{sourcedir}/collections-map-bidirectional-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -534,16 +572,17 @@ Second, Java arrays are relevant for basic types only, since storing multiple em
|
|||
|
||||
By default, Hibernate will choose a BINARY type, as supported by the current `Dialect`.
|
||||
|
||||
[[collections-array-binary-example]]
|
||||
.Binary arrays
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/BaseTypeBinaryArray.java[]
|
||||
include::{sourcedir}/ArrayTest.java[tags=collections-array-binary-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/BaseTypeBinaryArray.sql[]
|
||||
include::{sourcedir}/collections-array-binary-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -555,27 +594,33 @@ Collections not marked as such require a custom Hibernate `Type` and the collect
|
|||
|
||||
This is sometimes beneficial. Consider a use-case such as a `VARCHAR` column that represents a delimited list/set of Strings.
|
||||
|
||||
[[collections-comma-delimited-collection-example]]
|
||||
.Comma delimited collection
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/CommaDelimitedStringCollection.java[]
|
||||
include::{sourcedir}/BasicTypeCollectionTest.java[tags=collections-comma-delimited-collection-example,indent=0]
|
||||
|
||||
include::{sourcedir}/type/CommaDelimitedStringsJavaTypeDescriptor.java[tags=collections-comma-delimited-collection-example,indent=0]
|
||||
|
||||
include::{sourcedir}/type/CommaDelimitedStringsType.java[tags=collections-comma-delimited-collection-example,indent=0]
|
||||
----
|
||||
====
|
||||
|
||||
The developer can use the comma-delimited collection like any other collection we've discussed so far and Hibernate will take care of the type transformation part.
|
||||
The collection itself behaves like any other basic value type, as its lifecycle is bound to its owner entity.
|
||||
|
||||
[[collections-comma-delimited-collection-lifecycle-example]]
|
||||
.Comma delimited collection lifecycle
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/collections/CommaDelimitedStringCollectionLifecycle.java[]
|
||||
include::{sourcedir}/BasicTypeCollectionTest.java[tags=collections-comma-delimited-collection-lifecycle-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/collections/CommaDelimitedStringCollectionLifecycle.sql[]
|
||||
include::{sourcedir}/collections-comma-delimited-collection-lifecycle-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@NaturalId
|
||||
private String registrationNumber;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String registrationNumber) {
|
||||
this.registrationNumber = registrationNumber;
|
||||
}
|
||||
|
||||
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE} )
|
||||
private List<Address> addresses = new ArrayList<>();
|
||||
|
||||
public List<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void addAddress(Address address) {
|
||||
addresses.add(address);
|
||||
address.getOwners().add(this);
|
||||
}
|
||||
|
||||
public void removeAddress(Address address) {
|
||||
addresses.remove(address);
|
||||
address.getOwners().remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Person person = (Person) o;
|
||||
return Objects.equals(registrationNumber, person.registrationNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(registrationNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Address {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String street;
|
||||
|
||||
private String number;
|
||||
|
||||
private String postalCode;
|
||||
|
||||
@ManyToMany(mappedBy = "addresses")
|
||||
private List<Person> owners = new ArrayList<>();
|
||||
|
||||
public Address() {}
|
||||
|
||||
public Address(String street, String number, String postalCode) {
|
||||
this.street = street;
|
||||
this.number = number;
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
public List<Person> getOwners() {
|
||||
return owners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Address address = (Address) o;
|
||||
return Objects.equals(street, address.street) &&
|
||||
Objects.equals(number, address.number) &&
|
||||
Objects.equals(postalCode, address.postalCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(street, number, postalCode);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
Person person1 = new Person("ABC-123");
|
||||
Person person2 = new Person("DEF-456");
|
||||
|
||||
Address address1 = new Address("12th Avenue", "12A", "4005A");
|
||||
Address address2 = new Address("18th Avenue", "18B", "4007B");
|
||||
|
||||
person1.addAddress(address1);
|
||||
person1.addAddress(address2);
|
||||
|
||||
person2.addAddress(address1);
|
||||
|
||||
entityManager.persist(person1);
|
||||
entityManager.persist(person2);
|
||||
|
||||
entityManager.flush();
|
||||
|
||||
person1.removeAddress(address1);
|
|
@ -1,163 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@NaturalId
|
||||
private String registrationNumber;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<PersonAddress> addresses = new ArrayList<>();
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(String registrationNumber) {
|
||||
this.registrationNumber = registrationNumber;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public List<PersonAddress> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void addAddress(Address address) {
|
||||
PersonAddress personAddress = new PersonAddress(this, address);
|
||||
addresses.add(personAddress);
|
||||
address.getOwners().add(personAddress);
|
||||
}
|
||||
|
||||
public void removeAddress(Address address) {
|
||||
PersonAddress personAddress = new PersonAddress(this, address);
|
||||
address.getOwners().remove(personAddress);
|
||||
addresses.remove(personAddress);
|
||||
personAddress.setPerson(null);
|
||||
personAddress.setAddress(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Person person = (Person) o;
|
||||
return Objects.equals(registrationNumber, person.registrationNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(registrationNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class PersonAddress implements Serializable {
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
@Id
|
||||
@ManyToOne
|
||||
private Address address;
|
||||
|
||||
public PersonAddress() {}
|
||||
|
||||
public PersonAddress(Person person, Address address) {
|
||||
this.person = person;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PersonAddress that = (PersonAddress) o;
|
||||
return Objects.equals(person, that.person) &&
|
||||
Objects.equals(address, that.address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(person, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Address {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String street;
|
||||
|
||||
private String number;
|
||||
|
||||
private String postalCode;
|
||||
|
||||
@OneToMany(mappedBy = "address", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<PersonAddress> owners = new ArrayList<>();
|
||||
|
||||
public Address() {}
|
||||
|
||||
public Address(String street, String number, String postalCode) {
|
||||
this.street = street;
|
||||
this.number = number;
|
||||
this.postalCode = postalCode;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public String getPostalCode() {
|
||||
return postalCode;
|
||||
}
|
||||
|
||||
public List<PersonAddress> getOwners() {
|
||||
return owners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Address address = (Address) o;
|
||||
return Objects.equals(street, address.street) &&
|
||||
Objects.equals(number, address.number) &&
|
||||
Objects.equals(postalCode, address.postalCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(street, number, postalCode);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
Person person1 = new Person("ABC-123");
|
||||
Person person2 = new Person("DEF-456");
|
||||
|
||||
Address address1 = new Address("12th Avenue", "12A", "4005A");
|
||||
Address address2 = new Address("18th Avenue", "18B", "4007B");
|
||||
|
||||
entityManager.persist(person1);
|
||||
entityManager.persist(person2);
|
||||
|
||||
entityManager.persist(address1);
|
||||
entityManager.persist(address2);
|
||||
|
||||
person1.addAddress(address1);
|
||||
person1.addAddress(address2);
|
||||
|
||||
person2.addAddress(address1);
|
||||
|
||||
entityManager.flush();
|
||||
|
||||
person1.removeAddress(address1);
|
|
@ -1,80 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
|
||||
public void removePhone(Phone phone) {
|
||||
phones.remove(phone);
|
||||
phone.setPerson(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@NaturalId
|
||||
@Column(unique = true)
|
||||
private String number;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
Person person = new Person();
|
||||
Phone phone1 = new Phone("123-456-7890");
|
||||
Phone phone2 = new Phone("321-654-0987");
|
||||
|
||||
person.addPhone(phone1);
|
||||
person.addPhone(phone2);
|
||||
entityManager.persist(person);
|
||||
entityManager.flush();
|
||||
|
||||
person.removePhone(phone1);
|
|
@ -1,85 +0,0 @@
|
|||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String number;
|
||||
|
||||
@OneToOne(mappedBy = "phone", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private PhoneDetails details;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public PhoneDetails getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void addDetails(PhoneDetails details) {
|
||||
details.setPhone(this);
|
||||
this.details = details;
|
||||
}
|
||||
|
||||
public void removeDetails() {
|
||||
if (details != null) {
|
||||
details.setPhone(null);
|
||||
this.details = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class PhoneDetails {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String provider;
|
||||
|
||||
private String technology;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "phone_id")
|
||||
private Phone phone;
|
||||
|
||||
public PhoneDetails() {}
|
||||
|
||||
public PhoneDetails(String provider, String technology) {
|
||||
this.provider = provider;
|
||||
this.technology = technology;
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public String getTechnology() {
|
||||
return technology;
|
||||
}
|
||||
|
||||
public void setTechnology(String technology) {
|
||||
this.technology = technology;
|
||||
}
|
||||
|
||||
public Phone getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(Phone phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
Phone phone = new Phone("123-456-7890");
|
||||
PhoneDetails details = new PhoneDetails("T-Mobile", "GSM");
|
||||
|
||||
phone.addDetails(details);
|
||||
entityManager.persist(phone);
|
||||
|
||||
PhoneDetails otherDetails = new PhoneDetails("T-Mobile", "CDMA");
|
||||
otherDetails.setPhone(phone);
|
||||
entityManager.persist(otherDetails);
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
|
||||
//throws javax.persistence.PersistenceException: org.hibernate.HibernateException: More than one row with the given identifier was found: 1
|
||||
entityManager.find(Phone.class, phone.getId()).getDetails().getProvider();
|
|
@ -1,5 +0,0 @@
|
|||
Phone phone = new Phone("123-456-7890");
|
||||
PhoneDetails details = new PhoneDetails("T-Mobile", "GSM");
|
||||
|
||||
phone.addDetails(details);
|
||||
entityManager.persist(phone);
|
|
@ -1,47 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String number;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "person_id",
|
||||
foreignKey = @ForeignKey(name = "PERSON_ID_FK")
|
||||
)
|
||||
private Person person;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
Person person = new Person();
|
||||
entityManager.persist(person);
|
||||
|
||||
Phone phone = new Phone("123-456-7890");
|
||||
phone.setPerson(person);
|
||||
entityManager.persist(phone);
|
||||
|
||||
entityManager.flush();
|
||||
phone.setPerson(null);
|
|
@ -1,47 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE} )
|
||||
private List<Address> addresses = new ArrayList<>();
|
||||
|
||||
public List<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Address {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String street;
|
||||
|
||||
private String number;
|
||||
|
||||
public Address() {}
|
||||
|
||||
public Address(String street, String number) {
|
||||
this.street = street;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
Person person1 = new Person();
|
||||
Person person2 = new Person();
|
||||
|
||||
Address address1 = new Address("12th Avenue", "12A");
|
||||
Address address2 = new Address("18th Avenue", "18B");
|
||||
|
||||
person1.getAddresses().add(address1);
|
||||
person1.getAddresses().add(address2);
|
||||
|
||||
person2.getAddresses().add(address1);
|
||||
|
||||
entityManager.persist(person1);
|
||||
entityManager.persist(person2);
|
||||
|
||||
entityManager.flush();
|
||||
|
||||
person1.getAddresses().remove(address1);
|
|
@ -1,2 +0,0 @@
|
|||
Person person1 = entityManager.find(Person.class, personId);
|
||||
entityManager.remove(person1);
|
|
@ -1,40 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
Person person = new Person();
|
||||
Phone phone1 = new Phone("123-456-7890");
|
||||
Phone phone2 = new Phone("321-654-0987");
|
||||
|
||||
person.getPhones().add(phone1);
|
||||
person.getPhones().add(phone2);
|
||||
entityManager.persist(person);
|
||||
entityManager.flush();
|
||||
|
||||
person.getPhones().remove(phone1);
|
|
@ -1,66 +0,0 @@
|
|||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String number;
|
||||
|
||||
@OneToOne
|
||||
@JoinColumn(name = "details_id")
|
||||
private PhoneDetails details;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public PhoneDetails getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(PhoneDetails details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class PhoneDetails {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String provider;
|
||||
|
||||
private String technology;
|
||||
|
||||
public PhoneDetails() {}
|
||||
|
||||
public PhoneDetails(String provider, String technology) {
|
||||
this.provider = provider;
|
||||
this.technology = technology;
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public String getTechnology() {
|
||||
return technology;
|
||||
}
|
||||
|
||||
public void setTechnology(String technology) {
|
||||
this.technology = technology;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
private String[] phones;
|
||||
|
||||
public String[] getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void setPhones(String[] phones) {
|
||||
this.phones = phones;
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(
|
||||
mappedBy = "person",
|
||||
cascade = CascadeType.ALL
|
||||
)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
|
||||
public void removePhone(Phone phone) {
|
||||
phones.remove(phone);
|
||||
phone.setPerson(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
@Column(unique = true)
|
||||
@NaturalId
|
||||
private String number;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
person.addPhone(new Phone(1L, "landline", "028-234-9876"));
|
||||
person.addPhone(new Phone(2L, "mobile", "072-122-9876"));
|
||||
entityManager.flush();
|
||||
person.removePhone(person.getPhones().get(0));
|
|
@ -1,6 +0,0 @@
|
|||
@OneToMany(
|
||||
mappedBy = "person",
|
||||
cascade = CascadeType.ALL,
|
||||
orphanRemoval = true
|
||||
)
|
||||
private List<Phone> phones = new ArrayList<>();
|
|
@ -1,71 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@MapKey(name="type")
|
||||
@MapKeyEnumerated
|
||||
private Map<PhoneType, Phone> phoneRegister = new HashMap<>();
|
||||
|
||||
public Map<PhoneType, Phone> getPhoneRegister() {
|
||||
return phoneRegister;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phone.setPerson(this);
|
||||
phoneRegister.put(phone.getType(), phone);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private PhoneType type;
|
||||
|
||||
private String number;
|
||||
|
||||
private Date since;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(PhoneType type, String number, Date since) {
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
this.since = since;
|
||||
}
|
||||
|
||||
public PhoneType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Date getSince() {
|
||||
return since;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@OrderBy("number")
|
||||
private List<Phone> phones = new ArrayList<>();
|
|
@ -1,3 +0,0 @@
|
|||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@OrderColumn(name = "order_id")
|
||||
private List<Phone> phones = new ArrayList<>();
|
|
@ -1,86 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
private Set<Phone> phones = new HashSet<>();
|
||||
|
||||
public Set<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phones.add(phone);
|
||||
phone.setPerson(this);
|
||||
}
|
||||
|
||||
public void removePhone(Phone phone) {
|
||||
phones.remove(phone);
|
||||
phone.setPerson(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
@Column(unique = true)
|
||||
@NaturalId
|
||||
private String number;
|
||||
|
||||
@ManyToOne
|
||||
private Person person;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@SortNatural
|
||||
private SortedSet<Phone> phones = new TreeSet<>();
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@SortComparator(ReverseComparator.class)
|
||||
private SortedSet<Phone> phones = new TreeSet<>();
|
|
@ -1,17 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ElementCollection
|
||||
private List<String> phones = new ArrayList<>();
|
||||
|
||||
public List<String> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
//Throws java.lang.ClassCastException: org.hibernate.collection.internal.PersistentBag cannot be cast to java.util.ArrayList
|
||||
ArrayList<String> phones = ( ArrayList<String> ) person.getPhones();
|
|
@ -1,67 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Type(type = "comma_delimited_strings")
|
||||
private List<String> phones = new ArrayList<>();
|
||||
|
||||
public List<String> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommaDelimitedStringsJavaTypeDescriptor extends AbstractTypeDescriptor<List> {
|
||||
|
||||
public static final String DELIMITER = ",";
|
||||
|
||||
public CommaDelimitedStringsJavaTypeDescriptor() {
|
||||
super(
|
||||
List.class,
|
||||
new MutableMutabilityPlan<List>() {
|
||||
@Override
|
||||
protected List deepCopyNotNull(List value) {
|
||||
return new ArrayList(value);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(List value) {
|
||||
return ((List<String>) value).stream().collect(Collectors.joining(DELIMITER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List fromString(String string) {
|
||||
List<String> values = new ArrayList<>();
|
||||
Collections.addAll(values, string.split(DELIMITER));
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X unwrap(List value, Class<X> type, WrapperOptions options) {
|
||||
return (X) toString(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> List wrap(X value, WrapperOptions options) {
|
||||
return fromString((String) value);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommaDelimitedStringsType extends AbstractSingleColumnStandardBasicType<List> {
|
||||
|
||||
public CommaDelimitedStringsType() {
|
||||
super(
|
||||
VarcharTypeDescriptor.INSTANCE,
|
||||
new CommaDelimitedStringsJavaTypeDescriptor()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "comma_delimited_strings";
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
person.phones.add("027-123-4567");
|
||||
person.phones.add("028-234-9876");
|
||||
session.flush();
|
||||
|
||||
person.getPhones().remove(0);
|
||||
session.flush();
|
|
@ -1,3 +0,0 @@
|
|||
person.getPhones().clear();
|
||||
person.getPhones().add( "123-456-7890" );
|
||||
person.getPhones().add( "456-000-1234" );
|
|
@ -1 +0,0 @@
|
|||
person.getPhones().remove( 0 );
|
|
@ -1,53 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@ElementCollection
|
||||
@CollectionTable(name="phone_register")
|
||||
@Column(name="since")
|
||||
@MapKeyJoinColumn(name = "phone_id", referencedColumnName="id")
|
||||
private Map<Phone, Date> phoneRegister = new HashMap<>();
|
||||
|
||||
public Map<Phone, Date> getPhoneRegister() {
|
||||
return phoneRegister;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PhoneType {
|
||||
LAND_LINE,
|
||||
MOBILE
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public class Phone {
|
||||
|
||||
private PhoneType type;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(PhoneType type, String number) {
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public PhoneType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
person.getPhoneRegister().put(
|
||||
new Phone( PhoneType.LAND_LINE, "028-234-9876" ), new Date()
|
||||
);
|
||||
|
||||
person.getPhoneRegister().put(
|
||||
new Phone( PhoneType.MOBILE, "072-122-9876" ), new Date()
|
||||
);
|
|
@ -1,5 +0,0 @@
|
|||
@ElementCollection
|
||||
@OrderColumn(name = "order_id")
|
||||
private List<String> phones = new ArrayList<>();
|
||||
|
||||
person.getPhones().remove( 0 );
|
|
@ -1,39 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ElementCollection
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public class Phone {
|
||||
|
||||
private String type;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(String type, String number) {
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
person.getPhones().add( new Phone( "landline", "028-234-9876" ) );
|
||||
person.getPhones().add( new Phone( "mobile", "072-122-9876" ) );
|
|
@ -1,51 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person( Long id ) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone( Long id, String type, String number ) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
Person person = new Person( 1L );
|
||||
person.getPhones().add( new Phone( 1L, "landline", "028-234-9876" ) );
|
||||
person.getPhones().add( new Phone( 2L, "mobile", "072-122-9876" ) );
|
||||
entityManager.persist( person );
|
|
@ -1,79 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@SortComparator(ReverseComparator.class)
|
||||
private SortedSet<Phone> phones = new TreeSet<>();
|
||||
|
||||
public Set<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
public class ReverseComparator implements Comparator<Phone> {
|
||||
@Override
|
||||
public int compare(Phone o1, Phone o2) {
|
||||
return o2.compareTo(o1);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone implements Comparable<Phone> {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
@NaturalId
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Phone o) {
|
||||
return number.compareTo(o.getNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JoinTable(
|
||||
name="phone_register",
|
||||
joinColumns = @JoinColumn(name = "phone_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "person_id"))
|
||||
@MapKey(name="since")
|
||||
@MapKeyTemporal(TemporalType.TIMESTAMP)
|
||||
private Map<Date, Phone> phoneRegister = new HashMap<>();
|
||||
|
||||
public Map<Date, Phone> getPhoneRegister() {
|
||||
return phoneRegister;
|
||||
}
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
phoneRegister.put(phone.getSince(), phone);
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private PhoneType type;
|
||||
|
||||
private String number;
|
||||
|
||||
private Date since;
|
||||
|
||||
public Phone() {}
|
||||
|
||||
public Phone(PhoneType type, String number, Date since) {
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
this.since = since;
|
||||
}
|
||||
|
||||
public PhoneType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public Date getSince() {
|
||||
return since;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@SortNatural
|
||||
private SortedSet<Phone> phones = new TreeSet<>();
|
||||
|
||||
public Set<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone implements Comparable<Phone> {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
@NaturalId
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Phone o) {
|
||||
return number.compareTo(o.getNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@OrderBy("number")
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
@OneToMany(cascade = CascadeType.ALL)
|
||||
@OrderColumn(name = "order_id")
|
||||
private List<Phone> phones = new ArrayList<>();
|
|
@ -1,66 +0,0 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL)
|
||||
private Set<Phone> phones = new HashSet<>();
|
||||
|
||||
public Set<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class Phone {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String type;
|
||||
|
||||
@NaturalId
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(Long id, String type, String number) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Phone phone = (Phone) o;
|
||||
return Objects.equals(number, phone.number);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(number);
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String owner;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
private BigDecimal interestRate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRate() {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
public void setInterestRate(BigDecimal interestRate) {
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class DebitAccount extends Account {
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class CreditAccount extends Account {
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
@Entity(name = "DebitAccount")
|
||||
@PrimaryKeyJoinColumn(name = "account_id")
|
||||
public static class DebitAccount extends Account {
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "CreditAccount")
|
||||
@PrimaryKeyJoinColumn(name = "account_id")
|
||||
public static class CreditAccount extends Account {
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
List<Account> accounts = entityManager
|
||||
.createQuery( "select a from Account a" )
|
||||
.getResultList();
|
|
@ -1,72 +0,0 @@
|
|||
@MappedSuperclass
|
||||
public static class Account {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String owner;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
private BigDecimal interestRate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRate() {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
public void setInterestRate(BigDecimal interestRate) {
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class DebitAccount extends Account {
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class CreditAccount extends Account {
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String owner;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
private BigDecimal interestRate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRate() {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
public void setInterestRate(BigDecimal interestRate) {
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class DebitAccount extends Account {
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class CreditAccount extends Account {
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorFormula(
|
||||
"case when debitKey is not null " +
|
||||
"then 'Debit' " +
|
||||
"else ( " +
|
||||
" case when creditKey is not null " +
|
||||
" then 'Credit' " +
|
||||
" else 'Unknown' " +
|
||||
" end ) " +
|
||||
"end "
|
||||
)
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String owner;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
private BigDecimal interestRate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRate() {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
public void setInterestRate(BigDecimal interestRate) {
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@DiscriminatorValue(value = "Debit")
|
||||
public class DebitAccount extends Account {
|
||||
|
||||
private String debitKey;
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
private DebitAccount() {}
|
||||
|
||||
public DebitAccount(String debitKey) {
|
||||
this.debitKey = debitKey;
|
||||
}
|
||||
|
||||
public String getDebitKey() {
|
||||
return debitKey;
|
||||
}
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@DiscriminatorValue(value = "Credit")
|
||||
public static class CreditAccount extends Account {
|
||||
|
||||
private String creditKey;
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
private CreditAccount() {}
|
||||
|
||||
public CreditAccount(String creditKey) {
|
||||
this.creditKey = creditKey;
|
||||
}
|
||||
|
||||
public String getCreditKey() {
|
||||
return creditKey;
|
||||
}
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
DebitAccount debitAccount = new DebitAccount();
|
||||
debitAccount.setId(1L);
|
||||
debitAccount.setOwner("John Doe");
|
||||
debitAccount.setBalance(BigDecimal.valueOf(100));
|
||||
debitAccount.setInterestRate(BigDecimal.valueOf(1.5d));
|
||||
debitAccount.setOverdraftFee(BigDecimal.valueOf(25));
|
||||
|
||||
CreditAccount creditAccount = new CreditAccount();
|
||||
creditAccount.setId(2L);
|
||||
creditAccount.setOwner("John Doe");
|
||||
creditAccount.setBalance(BigDecimal.valueOf(1000));
|
||||
creditAccount.setInterestRate(BigDecimal.valueOf(1.9d));
|
||||
creditAccount.setCreditLimit(BigDecimal.valueOf(5000));
|
||||
|
||||
entityManager.persist(debitAccount);
|
||||
entityManager.persist(creditAccount);
|
|
@ -1,3 +0,0 @@
|
|||
List<Account> accounts = entityManager
|
||||
.createQuery( "select a from Account a" )
|
||||
.getResultList();
|
|
@ -1,73 +0,0 @@
|
|||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public class Account {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String owner;
|
||||
|
||||
private BigDecimal balance;
|
||||
|
||||
private BigDecimal interestRate;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BigDecimal getBalance() {
|
||||
return balance;
|
||||
}
|
||||
|
||||
public void setBalance(BigDecimal balance) {
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
public BigDecimal getInterestRate() {
|
||||
return interestRate;
|
||||
}
|
||||
|
||||
public void setInterestRate(BigDecimal interestRate) {
|
||||
this.interestRate = interestRate;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class DebitAccount extends Account {
|
||||
|
||||
private BigDecimal overdraftFee;
|
||||
|
||||
public BigDecimal getOverdraftFee() {
|
||||
return overdraftFee;
|
||||
}
|
||||
|
||||
public void setOverdraftFee(BigDecimal overdraftFee) {
|
||||
this.overdraftFee = overdraftFee;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public class CreditAccount extends Account {
|
||||
|
||||
private BigDecimal creditLimit;
|
||||
|
||||
public BigDecimal getCreditLimit() {
|
||||
return creditLimit;
|
||||
}
|
||||
|
||||
public void setCreditLimit(BigDecimal creditLimit) {
|
||||
this.creditLimit = creditLimit;
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
List<Account> accounts = entityManager
|
||||
.createQuery( "select a from Account a" )
|
||||
.getResultList();
|
|
@ -1,6 +1,6 @@
|
|||
[[entity-inheritance]]
|
||||
=== Inheritance
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/jpa/test/userguide/inheritance
|
||||
|
||||
Although relational database systems don't provide support for inheritance, Hibernate provides several strategies to leverage this object-oriented trait onto domain model entities:
|
||||
|
||||
|
@ -18,16 +18,17 @@ image:images/domain/inheritance/inheritance_class_diagram.svg[Inheritance class
|
|||
|
||||
When using `MappedSuperclass`, the inheritance is visible in the domain model only and ach database table contains both the base class and the subclass properties.
|
||||
|
||||
[[entity-inheritance-mapped-superclass-example]]
|
||||
.`@MappedSuperclass` inheritance
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/MappedSuperclass.java[]
|
||||
include::{sourcedir}/MappedSuperclassTest.java[tags=entity-inheritance-mapped-superclass-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/MappedSuperclass.sql[]
|
||||
include::{sourcedir}/entity-inheritance-mapped-superclass-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -49,32 +50,34 @@ Version and id properties are assumed to be inherited from the root class.
|
|||
When omitting an explicit inheritance strategy (e.g. `@Inheritance`), JPA will choose the `SINGLE_TABLE` strategy by default.
|
||||
====
|
||||
|
||||
[[entity-inheritance-single-table-example]]
|
||||
.Single Table inheritance
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTable.java[]
|
||||
include::{sourcedir}/SingleTableTest.java[tags=entity-inheritance-single-table-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTable.sql[]
|
||||
include::{sourcedir}/entity-inheritance-single-table-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
Each subclass in a hierarchy must define a unique discriminator value, which is used to differentiate between rows belonging to separate subclass types.
|
||||
If this is not specified, the `DTYPE` column is used as a discriminator, storing the associated subclass name.
|
||||
|
||||
[[entity-inheritance-single-table-persist-example]]
|
||||
.Single Table inheritance discriminator column
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTablePersist.java[]
|
||||
include::{sourcedir}/SingleTableTest.java[tags=entity-inheritance-single-table-persist-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTablePersist.sql[]
|
||||
include::{sourcedir}/entity-inheritance-single-table-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -111,16 +114,17 @@ There used to be `@org.hibernate.annotations.ForceDiscriminator` annotation whic
|
|||
Assuming a legacy database schema where the discriminator is based on inspecting a certain column,
|
||||
we can take advantage of the Hibernate specific `@DiscriminatorFormula` annotation and map the inheritance model as follows:
|
||||
|
||||
[[entity-inheritance-single-table-discriminator-formula-example]]
|
||||
.Single Table discriminator formula
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTableDiscriminatorFormula.java[]
|
||||
include::{sourcedir}/SingleTableDiscriminatorFormulaTest.java[tags=entity-inheritance-single-table-discriminator-formula-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTableDiscriminatorFormula.sql[]
|
||||
include::{sourcedir}/entity-inheritance-single-table-discriminator-formula-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -135,16 +139,17 @@ Because all subclass columns are stored in a single table, it's not possible to
|
|||
|
||||
When using polymorphic queries, only a single table is required to be scanned to fetch all associated subclass instances.
|
||||
|
||||
[[entity-inheritance-single-table-query-example]]
|
||||
.Single Table polymorphic query
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTableQuery.java[]
|
||||
include::{sourcedir}/SingleTableTest.java[tags=entity-inheritance-single-table-query-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/SingleTableQuery.sql[]
|
||||
include::{sourcedir}/entity-inheritance-single-table-query-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -158,16 +163,17 @@ An inherited state is retrieved by joining with the table of the superclass.
|
|||
A discriminator column is not required for this mapping strategy.
|
||||
Each subclass must, however, declare a table column holding the object identifier.
|
||||
|
||||
[[entity-inheritance-joined-table-example]]
|
||||
.Join Table
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTable.java[]
|
||||
include::{sourcedir}/JoinTableTest.java[tags=entity-inheritance-joined-table-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTable.sql[]
|
||||
include::{sourcedir}/entity-inheritance-joined-table-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -179,31 +185,33 @@ The table name still defaults to the non qualified class name.
|
|||
Also if `@PrimaryKeyJoinColumn` is not set, the primary key / foreign key columns are assumed to have the same names as the primary key columns of the primary table of the superclass.
|
||||
====
|
||||
|
||||
[[entity-inheritance-joined-table-primary-key-join-column-example]]
|
||||
.Join Table with `@PrimaryKeyJoinColumn`
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTablePrimaryKeyJoinColumn.java[]
|
||||
include::{sourcedir}/JoinTablePrimaryKeyJoinColumnTest.java[tags=entity-inheritance-joined-table-primary-key-join-column-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTablePrimaryKeyJoinColumn.sql[]
|
||||
include::{sourcedir}/entity-inheritance-joined-table-primary-key-join-column-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
When using polymorphic queries, the base class table must be joined with all subclass tables to fetch every associated subclass instance.
|
||||
|
||||
[[entity-inheritance-joined-table-query-example]]
|
||||
.Join Table polymorphic query
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTableQuery.java[]
|
||||
include::{sourcedir}/JoinTableTest.java[tags=entity-inheritance-joined-table-query-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/JoinTableQuery.sql[]
|
||||
include::{sourcedir}/entity-inheritance-joined-table-query-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -223,16 +231,17 @@ In Hibernate, it is not necessary to explicitly map such inheritance hierarchies
|
|||
You can map each class as a separate entity root.
|
||||
However, if you wish use polymorphic associations (e.g. an association to the superclass of your hierarchy), you need to use the union subclass mapping.
|
||||
|
||||
[[entity-inheritance-table-per-class-example]]
|
||||
.Table per class
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/TablePerClass.java[]
|
||||
include::{sourcedir}/TablePerClassTest.java[tags=entity-inheritance-table-per-class-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/TablePerClass.sql[]
|
||||
include::{sourcedir}/entity-inheritance-table-per-class-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
@ -242,12 +251,12 @@ When using polymorphic queries, a UNION is required to fetch the the base class
|
|||
====
|
||||
[source,java]
|
||||
----
|
||||
include::{sourcedir}/inheritance/TablePerClassQuery.java[]
|
||||
include::{sourcedir}/TablePerClassTest.java[tags=entity-inheritance-table-per-class-query-example,indent=0]
|
||||
----
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
include::{sourcedir}/inheritance/TablePerClassQuery.sql[]
|
||||
include::{sourcedir}/entity-inheritance-table-per-class-query-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -25,7 +25,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BidirectionalManyToManyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class ManyToManyBidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -38,6 +38,7 @@ public class BidirectionalManyToManyTest extends BaseEntityManagerFunctionalTest
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-many-to-many-bidirectional-lifecycle-example[]
|
||||
Person person1 = new Person( "ABC-123" );
|
||||
Person person2 = new Person( "DEF-456" );
|
||||
|
||||
|
@ -55,9 +56,11 @@ public class BidirectionalManyToManyTest extends BaseEntityManagerFunctionalTest
|
|||
entityManager.flush();
|
||||
|
||||
person1.removeAddress( address1 );
|
||||
//end::associations-many-to-many-bidirectional-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-many-to-many-bidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -173,4 +176,5 @@ public class BidirectionalManyToManyTest extends BaseEntityManagerFunctionalTest
|
|||
return Objects.hash( street, number, postalCode );
|
||||
}
|
||||
}
|
||||
//end::associations-many-to-many-bidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
@ -29,9 +29,9 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BidirectionalTwoOneToManyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class ManyToManyBidirectionalWithLinkEntityTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( BidirectionalTwoOneToManyTest.class );
|
||||
private static final Logger log = Logger.getLogger( ManyToManyBidirectionalWithLinkEntityTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -45,6 +45,7 @@ public class BidirectionalTwoOneToManyTest extends BaseEntityManagerFunctionalTe
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-many-to-many-bidirectional-with-link-entity-lifecycle-example[]
|
||||
Person person1 = new Person( "ABC-123" );
|
||||
Person person2 = new Person( "DEF-456" );
|
||||
|
||||
|
@ -66,9 +67,11 @@ public class BidirectionalTwoOneToManyTest extends BaseEntityManagerFunctionalTe
|
|||
|
||||
log.info( "Removing address" );
|
||||
person1.removeAddress( address1 );
|
||||
//end::associations-many-to-many-bidirectional-with-link-entity-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-many-to-many-bidirectional-with-link-entity-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person implements Serializable {
|
||||
|
||||
|
@ -247,4 +250,5 @@ public class BidirectionalTwoOneToManyTest extends BaseEntityManagerFunctionalTe
|
|||
return Objects.hash( street, number, postalCode );
|
||||
}
|
||||
}
|
||||
//end::associations-many-to-many-bidirectional-with-link-entity-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -25,9 +25,9 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class UnidirectionalManyToManyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class ManyToManyUnidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( UnidirectionalManyToManyTest.class );
|
||||
private static final Logger log = Logger.getLogger( ManyToManyUnidirectionalTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -40,6 +40,7 @@ public class UnidirectionalManyToManyTest extends BaseEntityManagerFunctionalTes
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-many-to-many-unidirectional-lifecycle-example[]
|
||||
Person person1 = new Person();
|
||||
Person person2 = new Person();
|
||||
|
||||
|
@ -57,6 +58,7 @@ public class UnidirectionalManyToManyTest extends BaseEntityManagerFunctionalTes
|
|||
entityManager.flush();
|
||||
|
||||
person1.getAddresses().remove( address1 );
|
||||
//end::associations-many-to-many-unidirectional-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -81,11 +83,14 @@ public class UnidirectionalManyToManyTest extends BaseEntityManagerFunctionalTes
|
|||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
log.info( "Remove" );
|
||||
//tag::associations-many-to-many-unidirectional-remove-example[]
|
||||
Person person1 = entityManager.find( Person.class, personId );
|
||||
entityManager.remove( person1 );
|
||||
//end::associations-many-to-many-unidirectional-remove-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-many-to-many-unidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -134,4 +139,5 @@ public class UnidirectionalManyToManyTest extends BaseEntityManagerFunctionalTes
|
|||
return number;
|
||||
}
|
||||
}
|
||||
//end::associations-many-to-many-unidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
|
@ -35,6 +35,7 @@ public class ManyToOneTest extends BaseEntityManagerFunctionalTestCase {
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-many-to-one-lifecycle-example[]
|
||||
Person person = new Person();
|
||||
entityManager.persist( person );
|
||||
|
||||
|
@ -44,9 +45,11 @@ public class ManyToOneTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
entityManager.flush();
|
||||
phone.setPerson( null );
|
||||
//end::associations-many-to-one-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-many-to-one-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -96,4 +99,5 @@ public class ManyToOneTest extends BaseEntityManagerFunctionalTestCase {
|
|||
this.person = person;
|
||||
}
|
||||
}
|
||||
//end::associations-many-to-one-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -27,7 +27,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BidirectionalOneToManyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class OneToManyBidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -40,6 +40,7 @@ public class BidirectionalOneToManyTest extends BaseEntityManagerFunctionalTestC
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-one-to-many-bidirectional-lifecycle-example[]
|
||||
Person person = new Person();
|
||||
Phone phone1 = new Phone( "123-456-7890" );
|
||||
Phone phone2 = new Phone( "321-654-0987" );
|
||||
|
@ -50,9 +51,11 @@ public class BidirectionalOneToManyTest extends BaseEntityManagerFunctionalTestC
|
|||
entityManager.flush();
|
||||
|
||||
person.removePhone( phone1 );
|
||||
//end::associations-one-to-many-bidirectional-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-one-to-many-bidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -138,4 +141,5 @@ public class BidirectionalOneToManyTest extends BaseEntityManagerFunctionalTestC
|
|||
return Objects.hash( number );
|
||||
}
|
||||
}
|
||||
//end::associations-one-to-many-bidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -23,7 +23,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class UnidirectionalOneToManyTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class OneToManyUnidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -36,6 +36,7 @@ public class UnidirectionalOneToManyTest extends BaseEntityManagerFunctionalTest
|
|||
@Test
|
||||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-one-to-many-unidirectional-lifecycle-example[]
|
||||
Person person = new Person();
|
||||
Phone phone1 = new Phone( "123-456-7890" );
|
||||
Phone phone2 = new Phone( "321-654-0987" );
|
||||
|
@ -46,9 +47,11 @@ public class UnidirectionalOneToManyTest extends BaseEntityManagerFunctionalTest
|
|||
entityManager.flush();
|
||||
|
||||
person.getPhones().remove( phone1 );
|
||||
//end::associations-one-to-many-unidirectional-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::associations-one-to-many-unidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -56,10 +59,6 @@ public class UnidirectionalOneToManyTest extends BaseEntityManagerFunctionalTest
|
|||
@GeneratedValue
|
||||
private Long id;
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
/*@JoinTable(name = "person_phone",
|
||||
joinColumns = @JoinColumn(name = "person_id", foreignKey = @ForeignKey(name = "PERSON_ID_FK")),
|
||||
inverseJoinColumns = @JoinColumn(name = "phone_id", foreignKey = @ForeignKey(name = "PHONE_ID_FK"))
|
||||
)*/
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public Person() {
|
||||
|
@ -94,4 +93,5 @@ public class UnidirectionalOneToManyTest extends BaseEntityManagerFunctionalTest
|
|||
return number;
|
||||
}
|
||||
}
|
||||
//end::associations-one-to-many-unidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -26,9 +26,9 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BidirectionalOneToOneTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class OneToOneBidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( BidirectionalOneToOneTest.class );
|
||||
private static final Logger log = Logger.getLogger( OneToOneBidirectionalTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -51,21 +51,30 @@ public class BidirectionalOneToOneTest extends BaseEntityManagerFunctionalTestCa
|
|||
|
||||
@Test
|
||||
public void testConstraint() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::associations-one-to-one-bidirectional-lifecycle-example[]
|
||||
Phone phone = new Phone( "123-456-7890" );
|
||||
PhoneDetails details = new PhoneDetails( "T-Mobile", "GSM" );
|
||||
|
||||
phone.addDetails( details );
|
||||
entityManager.persist( phone );
|
||||
//end::associations-one-to-one-bidirectional-lifecycle-example[]
|
||||
} );
|
||||
try {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Phone phone = new Phone( "123-456-7890" );
|
||||
PhoneDetails details = new PhoneDetails( "T-Mobile", "GSM" );
|
||||
|
||||
phone.addDetails( details );
|
||||
entityManager.persist( phone );
|
||||
Phone phone = entityManager.find( Phone.class, 1L );
|
||||
|
||||
//tag::associations-one-to-one-bidirectional-constraint-example[]
|
||||
PhoneDetails otherDetails = new PhoneDetails( "T-Mobile", "CDMA" );
|
||||
otherDetails.setPhone( phone );
|
||||
entityManager.persist( otherDetails );
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
|
||||
//throws javax.persistence.PersistenceException: org.hibernate.HibernateException: More than one row with the given identifier was found: 1
|
||||
phone = entityManager.find( Phone.class, phone.getId() );
|
||||
//end::associations-one-to-one-bidirectional-constraint-example[]
|
||||
phone.getDetails().getProvider();
|
||||
} );
|
||||
Assert.fail( "Expected: HHH000327: Error performing load command : org.hibernate.HibernateException: More than one row with the given identifier was found: 1" );
|
||||
|
@ -75,6 +84,7 @@ public class BidirectionalOneToOneTest extends BaseEntityManagerFunctionalTestCa
|
|||
}
|
||||
}
|
||||
|
||||
//tag::associations-one-to-one-bidirectional-example[]
|
||||
@Entity(name = "Phone")
|
||||
public static class Phone {
|
||||
|
||||
|
@ -162,4 +172,5 @@ public class BidirectionalOneToOneTest extends BaseEntityManagerFunctionalTestCa
|
|||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
//end::associations-one-to-one-bidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
@ -21,7 +21,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class OneToOneTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class OneToOneUnidirectionalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -43,6 +43,7 @@ public class OneToOneTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::associations-one-to-one-unidirectional-example[]
|
||||
@Entity(name = "Phone")
|
||||
public static class Phone {
|
||||
|
||||
|
@ -111,4 +112,5 @@ public class OneToOneTest extends BaseEntityManagerFunctionalTestCase {
|
|||
this.technology = technology;
|
||||
}
|
||||
}
|
||||
//end::associations-one-to-one-unidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.association;
|
||||
package org.hibernate.jpa.test.userguide.associations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection.type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class CommaDelimitedStringsJavaTypeDescriptor extends AbstractTypeDescriptor<List> {
|
||||
|
||||
public static final String DELIMITER = ",";
|
||||
|
||||
public CommaDelimitedStringsJavaTypeDescriptor() {
|
||||
super(
|
||||
List.class,
|
||||
new MutableMutabilityPlan<List>() {
|
||||
@Override
|
||||
protected List deepCopyNotNull(List value) {
|
||||
return new ArrayList( value );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(List value) {
|
||||
return ( (List<String>) value ).stream().collect( Collectors.joining( DELIMITER ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List fromString(String string) {
|
||||
List<String> values = new ArrayList<>();
|
||||
Collections.addAll( values, string.split( DELIMITER ) );
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X unwrap(List value, Class<X> type, WrapperOptions options) {
|
||||
return (X) toString( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> List wrap(X value, WrapperOptions options) {
|
||||
return fromString( (String) value );
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
@ -18,7 +18,7 @@ import static org.hibernate.jpa.test.util.TransactionUtil.doInJPA;
|
|||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class UnidirectionalArrayTest extends BaseEntityManagerFunctionalTestCase {
|
||||
public class ArrayTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -45,6 +45,7 @@ public class UnidirectionalArrayTest extends BaseEntityManagerFunctionalTestCase
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::collections-array-binary-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -67,4 +68,5 @@ public class UnidirectionalArrayTest extends BaseEntityManagerFunctionalTestCase
|
|||
this.phones = phones;
|
||||
}
|
||||
}
|
||||
//end::collections-array-binary-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -13,7 +13,7 @@ import javax.persistence.Id;
|
|||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.jpa.test.userguide.collection.type.CommaDelimitedStringsType;
|
||||
import org.hibernate.jpa.test.userguide.collections.type.CommaDelimitedStringsType;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
@ -41,14 +41,14 @@ public class BasicTypeCollectionTest extends BaseCoreFunctionalTestCase {
|
|||
doInHibernate( this::sessionFactory, session -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
session.persist( person );
|
||||
|
||||
//tag::collections-comma-delimited-collection-lifecycle-example[]
|
||||
person.phones.add( "027-123-4567" );
|
||||
person.phones.add( "028-234-9876" );
|
||||
session.persist( person );
|
||||
} );
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Person person = session.get( Person.class, 1L );
|
||||
log.infov( "Remove one element" );
|
||||
session.flush();
|
||||
person.getPhones().remove( 0 );
|
||||
//end::collections-comma-delimited-collection-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ public class BasicTypeCollectionTest extends BaseCoreFunctionalTestCase {
|
|||
return configuration;
|
||||
}
|
||||
|
||||
//tag::collections-comma-delimited-collection-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -74,4 +75,5 @@ public class BasicTypeCollectionTest extends BaseCoreFunctionalTestCase {
|
|||
return phones;
|
||||
}
|
||||
}
|
||||
//end::collections-comma-delimited-collection-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -14,7 +14,6 @@ import javax.persistence.Id;
|
|||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -50,10 +49,12 @@ public class BasicTypeElementCollectionTest extends BaseEntityManagerFunctionalT
|
|||
@Test
|
||||
public void testProxies() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
Assert.assertEquals( 2, person.getPhones().size() );
|
||||
try {
|
||||
//tag::collections-collection-proxy-usage-example[]
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
//Throws java.lang.ClassCastException: org.hibernate.collection.internal.PersistentBag cannot be cast to java.util.ArrayList
|
||||
ArrayList<String> phones = (ArrayList<String>) person.getPhones();
|
||||
//end::collections-collection-proxy-usage-example[]
|
||||
}
|
||||
catch (Exception expected) {
|
||||
log.error( "Failure", expected );
|
||||
|
@ -66,17 +67,22 @@ public class BasicTypeElementCollectionTest extends BaseEntityManagerFunctionalT
|
|||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
log.info( "Clear element collection and add element" );
|
||||
//tag::collections-value-type-collection-lifecycle-example[]
|
||||
person.getPhones().clear();
|
||||
person.getPhones().add( "123-456-7890" );
|
||||
person.getPhones().add( "456-000-1234" );
|
||||
//end::collections-value-type-collection-lifecycle-example[]
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
log.info( "Remove one element" );
|
||||
//tag::collections-value-type-collection-remove-example[]
|
||||
person.getPhones().remove( 0 );
|
||||
//end::collections-value-type-collection-remove-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::collections-collection-proxy-entity-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -90,4 +96,5 @@ public class BasicTypeElementCollectionTest extends BaseEntityManagerFunctionalT
|
|||
return phones;
|
||||
}
|
||||
}
|
||||
//end::collections-collection-proxy-entity-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -47,7 +47,9 @@ public class BasicTypeOrderColumnElementCollectionTest extends BaseEntityManager
|
|||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = entityManager.find( Person.class, 1L );
|
||||
log.info( "Remove one element" );
|
||||
//tag::collections-value-type-collection-order-column-remove-example[]
|
||||
person.getPhones().remove( 0 );
|
||||
//end::collections-value-type-collection-order-column-remove-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -57,9 +59,11 @@ public class BasicTypeOrderColumnElementCollectionTest extends BaseEntityManager
|
|||
@Id
|
||||
private Long id;
|
||||
|
||||
//tag::collections-value-type-collection-order-column-remove-entity-example[]
|
||||
@ElementCollection
|
||||
@OrderColumn(name = "order_id")
|
||||
private List<String> phones = new ArrayList<>();
|
||||
//end::collections-value-type-collection-order-column-remove-entity-example[]
|
||||
|
||||
public List<String> getPhones() {
|
||||
return phones;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -53,8 +53,11 @@ public class BidirectionalBagOrphanRemovalTest extends BaseEntityManagerFunction
|
|||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
//tag::collections-bidirectional-bag-orphan-removal-example[]
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
//end::collections-bidirectional-bag-orphan-removal-example[]
|
||||
|
||||
public Person() {
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -41,13 +41,16 @@ public class BidirectionalBagTest extends BaseEntityManagerFunctionalTestCase {
|
|||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = new Person( 1L );
|
||||
entityManager.persist( person );
|
||||
//tag::collections-bidirectional-bag-lifecycle-example[]
|
||||
person.addPhone( new Phone( 1L, "landline", "028-234-9876" ) );
|
||||
person.addPhone( new Phone( 2L, "mobile", "072-122-9876" ) );
|
||||
entityManager.flush();
|
||||
person.removePhone( person.getPhones().get( 0 ) );
|
||||
//end::collections-bidirectional-bag-lifecycle-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::collections-bidirectional-bag-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -139,4 +142,5 @@ public class BidirectionalBagTest extends BaseEntityManagerFunctionalTestCase {
|
|||
return Objects.hash( number );
|
||||
}
|
||||
}
|
||||
//end::collections-bidirectional-bag-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -61,6 +61,7 @@ public class BidirectionalMapTest extends BaseEntityManagerFunctionalTestCase {
|
|||
MOBILE
|
||||
}
|
||||
|
||||
//tag::collections-map-bidirectional-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -133,4 +134,5 @@ public class BidirectionalMapTest extends BaseEntityManagerFunctionalTestCase {
|
|||
this.person = person;
|
||||
}
|
||||
}
|
||||
//end::collections-map-bidirectional-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -57,9 +57,12 @@ public class BidirectionalOrderByListTest extends BaseEntityManagerFunctionalTes
|
|||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
//tag::collections-bidirectional-ordered-list-order-by-example[]
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@OrderBy("number")
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
//end::collections-bidirectional-ordered-list-order-by-example[]
|
||||
|
||||
public Person() {
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -57,9 +57,12 @@ public class BidirectionalOrderColumnListTest extends BaseEntityManagerFunctiona
|
|||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
//tag::collections-bidirectional-ordered-list-order-column-example[]
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@OrderColumn(name = "order_id")
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
//end::collections-bidirectional-ordered-list-order-column-example[]
|
||||
|
||||
public Person() {
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
|
@ -59,11 +59,13 @@ public class BidirectionalSetTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::collections-bidirectional-set-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
private Set<Phone> phones = new HashSet<>();
|
||||
|
||||
|
@ -150,4 +152,5 @@ public class BidirectionalSetTest extends BaseEntityManagerFunctionalTestCase {
|
|||
return Objects.hash( number );
|
||||
}
|
||||
}
|
||||
//end::collections-bidirectional-set-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -71,9 +71,12 @@ public class BidirectionalSortedSetTest extends BaseEntityManagerFunctionalTestC
|
|||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
//tag::collections-bidirectional-sorted-set-example[]
|
||||
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL)
|
||||
@SortNatural
|
||||
private SortedSet<Phone> phones = new TreeSet<>();
|
||||
//end::collections-bidirectional-sorted-set-example[]
|
||||
|
||||
public Person() {
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
@ -43,8 +43,14 @@ public class ElementCollectionMapTest extends BaseEntityManagerFunctionalTestCas
|
|||
public void testLifecycle() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = new Person( 1L );
|
||||
person.getPhoneRegister().put( new Phone( PhoneType.LAND_LINE, "028-234-9876" ), new Date() );
|
||||
person.getPhoneRegister().put( new Phone( PhoneType.MOBILE, "072-122-9876" ), new Date() );
|
||||
//tag::collections-map-value-type-entity-key-add-example[]
|
||||
person.getPhoneRegister().put(
|
||||
new Phone( PhoneType.LAND_LINE, "028-234-9876" ), new Date()
|
||||
);
|
||||
person.getPhoneRegister().put(
|
||||
new Phone( PhoneType.MOBILE, "072-122-9876" ), new Date()
|
||||
);
|
||||
//end::collections-map-value-type-entity-key-add-example[]
|
||||
entityManager.persist( person );
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
@ -54,6 +60,7 @@ public class ElementCollectionMapTest extends BaseEntityManagerFunctionalTestCas
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::collections-map-value-type-entity-key-example[]
|
||||
public enum PhoneType {
|
||||
LAND_LINE,
|
||||
MOBILE
|
||||
|
@ -106,4 +113,5 @@ public class ElementCollectionMapTest extends BaseEntityManagerFunctionalTestCas
|
|||
return number;
|
||||
}
|
||||
}
|
||||
//end::collections-map-value-type-entity-key-example[]
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.userguide.collection;
|
||||
package org.hibernate.jpa.test.userguide.collections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -36,12 +36,15 @@ public class EmbeddableTypeElementCollectionTest extends BaseEntityManagerFuncti
|
|||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Person person = new Person();
|
||||
person.id = 1L;
|
||||
//tag::collections-embeddable-type-collection-lifecycle-example[]
|
||||
person.getPhones().add( new Phone( "landline", "028-234-9876" ) );
|
||||
person.getPhones().add( new Phone( "mobile", "072-122-9876" ) );
|
||||
//end::collections-embeddable-type-collection-lifecycle-example[]
|
||||
entityManager.persist( person );
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::collections-embeddable-type-collection-lifecycle-entity-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -79,4 +82,5 @@ public class EmbeddableTypeElementCollectionTest extends BaseEntityManagerFuncti
|
|||
return number;
|
||||
}
|
||||
}
|
||||
//end::collections-embeddable-type-collection-lifecycle-entity-example[]
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue