HHH-13041 - Move @Any and other association mappings to the association chapter

This commit is contained in:
John Lin 2018-10-17 13:09:08 +08:00 committed by Vlad Mihalcea
parent 06b559e46e
commit fecb12cff7
47 changed files with 1398 additions and 879 deletions

View File

@ -633,14 +633,14 @@ You should use either the JPA <<annotations-jpa-access>> or the Hibernate native
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Any.html[`@Any`] annotation is used to define the *any-to-one* association
which can point to one one of several entity types.
See the <<chapters/domain/basic_types.adoc#mapping-column-any,`@Any` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-any,`@Any` mapping>> section for more info.
[[annotations-hibernate-anymetadef]]
==== `@AnyMetaDef`
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/AnyMetaDef.html[`@AnyMetaDef`] annotation is used to provide metadata about an `@Any` or `@ManyToAny` mapping.
See the <<chapters/domain/basic_types.adoc#mapping-column-any,`@Any` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-any,`@Any` mapping>> section for more info.
[[annotations-hibernate-anymetadefs]]
==== `@AnyMetaDefs`
@ -816,14 +816,14 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Filter.html[`@Filter`] annotation is used to add filters to an entity or the target entity of a collection.
See the <<chapters/domain/basic_types.adoc#mapping-filter-example,Filter mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-filter,Filter mapping>> section for more info.
[[annotations-hibernate-filterdef]]
==== `@FilterDef`
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/FilterDef.html[`@FilterDef`] annotation is used to specify a `@Filter` definition (name, default condition and parameter types, if any).
See the <<chapters/domain/basic_types.adoc#mapping-filter-example,Filter mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-filter,Filter mapping>> section for more info.
[[annotations-hibernate-filterdefs]]
==== `@FilterDefs`
@ -835,7 +835,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/FilterJoinTable.html[`@FilterJoinTable`] annotation is used to add `@Filter` capabilities to a join table collection.
See the <<chapters/domain/basic_types.adoc#mapping-column-filter-join-table,FilterJoinTable mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-filter-join-table,FilterJoinTable mapping>> section for more info.
[[annotations-hibernate-filterjointables]]
==== `@FilterJoinTables`
@ -907,7 +907,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinColumnOrFormula.html[`@JoinColumnOrFormula`] annotation is used to specify that the entity association is resolved either through a FOREIGN KEY join (e.g. <<annotations-jpa-joincolumn>>) or using the result of a given SQL formula (e.g. <<annotations-hibernate-joinformula>>).
See the <<chapters/domain/basic_types.adoc#mapping-JoinColumnOrFormula,`@JoinColumnOrFormula` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-JoinColumnOrFormula,`@JoinColumnOrFormula` mapping>> section for more info.
[[annotations-hibernate-joincolumnsorformulas]]
==== `@JoinColumnsOrFormulas`
@ -918,7 +918,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinFormula.html[`@JoinFormula`] annotation is used as a replacement for <<annotations-jpa-joincolumn>> when the association does not have a dedicated FOREIGN KEY column.
See the <<chapters/domain/basic_types.adoc#mapping-JoinFormula,`@JoinFormula` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-JoinFormula,`@JoinFormula` mapping>> section for more info.
[[annotations-hibernate-lazycollection]]
==== `@LazyCollection`
@ -983,7 +983,7 @@ See the <<chapters/query/native/Native.adoc#sql-custom-crud-example, Custom CRUD
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/ManyToAny.html[`@ManyToAny`] annotation is used to specify a many-to-one association when the target type is dynamically resolved.
See the <<chapters/domain/basic_types.adoc#mapping-column-many-to-any, `@ManyToAny` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-many-to-any, `@ManyToAny` mapping>> section for more info.
[[annotations-hibernate-mapkeytype]]
==== `@MapKeyType`
@ -997,7 +997,7 @@ See the <<chapters/domain/collections.adoc#collections-map-custom-key-type, `@Ma
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/MetaValue.html[`@MetaValue`] annotation is used by the <<annotations-hibernate-anymetadef>> annotation to specify the association between a given discriminator value and an entity type.
See the <<chapters/domain/basic_types.adoc#mapping-column-any,`@Any` mapping>> section for more info.
See the <<chapters/domain/associations.adoc#associations-any,`@Any` mapping>> section for more info.
[[annotations-hibernate-namednativequeries]]
==== `@NamedNativeQueries`
@ -1122,7 +1122,7 @@ See the <<chapters/domain/collections.adoc#collections-customizing-ordered-by-sq
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/ParamDef.html[`@ParamDef`] annotation is used in conjunction with <<annotations-hibernate-filterdef>> so that the Hibernate Filter can be customized with runtime-provided parameter values.
See the <<chapters/domain/basic_types.adoc#mapping-filter-example,Filter mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-filter-example,Filter mapping>> section for more info.
[[annotations-hibernate-parameter]]
==== `@Parameter`
@ -1135,7 +1135,7 @@ like <<annotations-hibernate-collectiontype>>, <<annotations-hibernate-genericge
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Parent.html[`@Parent`] annotation is used to specify that the currently annotated embeddable attribute references back the owning entity.
See the <<chapters/domain/basic_types.adoc#mapping-Parent,`@Parent` mapping>> section for more info.
See the <<chapters/domain/embeddables.adoc#embeddable-Parent,`@Parent` mapping>> section for more info.
[[annotations-hibernate-persister]]
==== `@Persister`
@ -1237,7 +1237,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
The alias (e.g. `myAlias`) can then be used in the `@Filter` `condition` clause using the `{alias}` (e.g. `{myAlias}`) placeholder.
See the <<chapters/domain/basic_types.adoc#mapping-column-filter-sql-fragment-alias,`@SqlFragmentAlias` mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-filter-sql-fragment-alias,`@SqlFragmentAlias` mapping>> section for more info.
[[annotations-hibernate-sqlinsert]]
==== `@SQLInsert`
@ -1287,7 +1287,7 @@ The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibern
==== `@Target`
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Target.html[`@Target`] annotation is used to specify an explicit target implementation when the currently annotated association is using an interface type.
See the <<chapters/domain/basic_types.adoc#mapping-Target,`@Target` mapping>> section for more info.
See the <<chapters/domain/embeddables.adoc#embeddable-Target,`@Target` mapping>> section for more info.
[[annotations-hibernate-tuplizer]]
==== `@Tuplizer`
@ -1349,11 +1349,11 @@ See the <<chapters/domain/basic_types.adoc#mapping-database-generated-value-exam
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Where.html[`@Where`] annotation is used to specify a custom SQL `WHERE` clause used when fetching an entity or a collection.
See the <<chapters/domain/basic_types.adoc#mapping-where-example,`@Where` mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-where-example,`@Where` mapping>> section for more info.
[[annotations-hibernate-wherejointable]]
==== `@WhereJoinTable`
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/WhereJoinTable.html[`@WhereJoinTable`] annotation is used to specify a custom SQL `WHERE` clause used when fetching a join collection table.
See the <<chapters/domain/basic_types.adoc#mapping-where-join-table, `@WhereJoinTable` mapping>> section for more info.
See the <<chapters/pc/PersistenceContext.adoc#pc-where-join-table, `@WhereJoinTable` mapping>> section for more info.

View File

@ -485,3 +485,276 @@ Hibernate is not going to throw any exception, and it will assign a value of `nu
include::{sourcedir}/NotFoundTest.java[tags=associations-not-found-non-existing-find-example,indent=0]
----
====
[[associations-any]]
==== `@Any` mapping
The `@Any` mapping is useful to emulate a unidirectional `@ManyToOne` association when there can be multiple target entities.
Because the `@Any` mapping defines a polymorphic association to classes from multiple tables,
this association type requires the FK column which provides the associated parent identifier and
a metadata information for the associated entity type.
[NOTE]
====
It is impossible to specify a foreign key constraint for this kind of association.
This is not the usual way of mapping polymorphic associations and you should use this only in special cases (e.g. audit logs, user session data, etc).
====
The `@Any` annotation describes the column holding the metadata information.
To link the value of the metadata information and an actual entity type, the `@AnyDef` and `@AnyDefs` annotations are used.
The `metaType` attribute allows the application to specify a custom type that maps database column values to persistent classes that have identifier properties of the type specified by `idType`.
You must specify the mapping from values of the `metaType` to class names.
For the next examples, consider the following `Property` class hierarchy:
[[associations-any-property-example]]
.`Property` class hierarchy
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/Property.java[tags=associations-any-property-example]
include::{sourcedir}/any/IntegerProperty.java[tags=associations-any-property-example]
include::{sourcedir}/any/StringProperty.java[tags=associations-any-property-example]
----
====
A `PropertyHolder` can reference any such property, and, because each `Property` belongs to a separate table, the `@Any` annotation is, therefore, required.
[[associations-any-example]]
.`@Any` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/PropertyHolder.java[tags=associations-any-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-any-example.sql[]
----
====
As you can see, there are two columns used to reference a `Property` instance: `property_id` and `property_type`.
The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
while the `property_type` is used to match the `string_property` or the `integer_property` table.
The table resolving mapping is defined by the `metaDef` attribute which references an `@AnyMetaDef` mapping.
Although the `@AnyMetaDef` mapping could be set right next to the `@Any` annotation,
it's good practice to reuse it, therefore it makes sense to configure it on a class or package-level basis.
The `package-info.java` contains the `@AnyMetaDef` mapping:
[[associations-any-meta-def-example]]
.`@Any` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/package-info.java[tags=associations-any-meta-def-example]
----
====
[NOTE]
====
It is recommended to place the `@AnyMetaDef` mapping as a package metadata.
====
To see the `@Any` annotation in action, consider the next examples.
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
the `StringProperty` entity with a `PropertyHolder`,
Hibernate will generate the following SQL queries:
[[associations-any-persist-example]]
.`@Any` mapping persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/AnyTest.java[tags=associations-any-persist-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-any-persist-example.sql[]
----
====
When fetching the `PropertyHolder` entity and navigating its `property` association,
Hibernate will fetch the associated `StringProperty` entity like this:
[[associations-any-query-example]]
.`@Any` mapping query example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/AnyTest.java[tags=associations-any-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-any-query-example.sql[]
----
====
[[associations-many-to-any]]
===== `@ManyToAny` mapping
While the `@Any` mapping is useful to emulate a `@ManyToOne` association when there can be multiple target entities,
to emulate a `@OneToMany` association, the `@ManyToAny` annotation must be used.
In the following example, the `PropertyRepository` entity has a collection of `Property` entities.
The `repository_properties` link table holds the associations between `PropertyRepository` and `Property` entities.
[[associations-many-to-any-example]]
.`@ManyToAny` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/PropertyRepository.java[tags=associations-many-to-any-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-many-to-any-example.sql[]
----
====
To see the `@ManyToAny` annotation in action, consider the next examples.
If we persist an `IntegerProperty` as well as a `StringProperty` entity,
and associate both of them with a `PropertyRepository` parent entity,
Hibernate will generate the following SQL queries:
[[associations-many-to-any-persist-example]]
.`@ManyToAny` mapping persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/ManyToAnyTest.java[tags=associations-many-to-any-persist-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-many-to-any-persist-example.sql[]
----
====
When fetching the `PropertyRepository` entity and navigating its `properties` association,
Hibernate will fetch the associated `IntegerProperty` and `StringProperty` entities like this:
[[associations-many-to-any-query-example]]
.`@ManyToAny` mapping query example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/any/ManyToAnyTest.java[tags=associations-many-to-any-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-many-to-any-query-example.sql[]
----
====
[[associations-JoinFormula]]
==== `@JoinFormula` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinFormula.html[`@JoinFormula`] annotation is used to customize the join between a child Foreign Key and a parent row Primary Key.
[[associations-JoinFormula-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinFormulaTest.java[tags=associations-JoinFormula-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-JoinFormula-example.sql[]
----
====
The `country` association in the `User` entity is mapped by the country identifier provided by the `phoneNumber` property.
Considering we have the following entities:
[[associations-JoinFormula-persistence-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinFormulaTest.java[tags=associations-JoinFormula-persistence-example]
----
====
When fetching the `User` entities, the `country` property is mapped by the `@JoinFormula` expression:
[[associations-JoinFormula-fetching-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinFormulaTest.java[tags=associations-JoinFormula-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-JoinFormula-fetching-example.sql[]
----
====
Therefore, the `@JoinFormula` annotation is used to define a custom join association between the parent-child association.
[[associations-JoinColumnOrFormula]]
==== `@JoinColumnOrFormula` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinColumnOrFormula.html[`@JoinColumnOrFormula`] annotation is used to customize the join between a child Foreign Key and a parent row Primary Key when we need to take into consideration a column value as well as a `@JoinFormula`.
[[associations-JoinColumnOrFormula-example]]
.`@JoinColumnOrFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinColumnOrFormulaTest.java[tags=associations-JoinColumnOrFormula-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-JoinColumnOrFormula-example.sql[]
----
====
The `country` association in the `User` entity is mapped by the `language` property value and the associated `Country` `is_default` column value.
Considering we have the following entities:
[[associations-JoinColumnOrFormula-persistence-example]]
.`@JoinColumnOrFormula` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinColumnOrFormulaTest.java[tags=associations-JoinColumnOrFormula-persistence-example]
----
====
When fetching the `User` entities, the `country` property is mapped by the `@JoinColumnOrFormula` expression:
[[associations-JoinColumnOrFormula-fetching-example]]
.`@JoinColumnOrFormula` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/JoinColumnOrFormulaTest.java[tags=associations-JoinColumnOrFormula-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/associations-JoinColumnOrFormula-fetching-example.sql[]
----
====
Therefore, the `@JoinColumnOrFormula` annotation is used to define a custom join association between the parent-child association.

View File

@ -1718,736 +1718,3 @@ include::{extrasdir}/basic/mapping-column-formula-persistence-example.sql[]
====
The SQL fragment can be as complex as you want and even include subselects.
====
[[mapping-column-where]]
==== `@Where`
Sometimes, you want to filter out entities or collections using custom SQL criteria.
This can be achieved using the `@Where` annotation, which can be applied to entities and collections.
[[mapping-where-example]]
.`@Where` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereTest.java[tags=mapping-where-example]
----
====
If the database contains the following entities:
[[mapping-where-persistence-example]]
.Persisting and fetching entities with a `@Where` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereTest.java[tags=mapping-where-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-where-persistence-example.sql[]
----
====
When executing an `Account` entity query, Hibernate is going to filter out all records that are not active.
[[mapping-where-entity-query-example]]
.Query entities mapped with `@Where`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereTest.java[tags=mapping-where-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-where-entity-query-example.sql[]
----
====
When fetching the `debitAccounts` or the `creditAccounts` collections, Hibernate is going to apply the `@Where` clause filtering criteria to the associated child entities.
[[mapping-where-collection-query-example]]
.Traversing collections mapped with `@Where`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereTest.java[tags=mapping-where-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-where-collection-query-example.sql[]
----
====
[[mapping-where-join-table]]
==== `@WhereJoinTable`
Just like `@Where` annotation, `@WhereJoinTable` is used to filter out collections using a joined table (e.g. @ManyToMany association).
[[mapping-where-join-table-example]]
.`@WhereJoinTable` mapping example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereJoinTableTest.java[tags=mapping-where-join-table-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-where-join-table-example.sql[]
----
====
In the example above, the current week `Reader` entities are included in the `currentWeekReaders` collection
which uses the `@WhereJoinTable` annotation to filter the joined table rows according to the provided SQL clause.
Considering that the following two `Book_Reader` entries are added into our system:
[[mapping-where-join-table-persist-example]]
.`@WhereJoinTable` test data
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereJoinTableTest.java[tags=mapping-where-join-table-persist-example]
----
====
When fetching the `currentWeekReaders` collection, Hibernate is going to find one one entry:
[[mapping-where-join-table-fetch-example]]
.`@WhereJoinTable` fetch example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/WhereJoinTableTest.java[tags=mapping-where-join-table-fetch-example]
----
====
[[mapping-column-filter]]
==== `@Filter`
The `@Filter` annotation is another way to filter out entities or collections using custom SQL criteria.
Unlike the `@Where` annotation, `@Filter` allows you to parameterize the filter clause at runtime.
Now, considering we have the following `Account` entity:
[[mapping-filter-account-example]]
.`@Filter` mapping entity-level usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-Account-example]
----
====
[NOTE]
====
Notice that the `active` property is mapped to the `active_status` column.
This mapping was done to show you that the `@Filter` condition uses a SQL condition and not a JPQL filtering predicate.
====
As already explained, we can also apply the `@Filter` annotation for collections as illustrated by the `Client` entity:
[[mapping-filter-client-example]]
.`@Filter` mapping collection-level usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-Client-example]
----
====
If we persist a `Client` with three associated `Account` entities,
Hibernate will execute the following SQL statements:
[[mapping-filter-persistence-example]]
.Persisting and fetching entities with a `@Filter` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-persistence-example.sql[]
----
====
By default, without explicitly enabling the filter, Hibernate is going to fetch all `Account` entities.
[[mapping-no-filter-entity-query-example]]
.Query entities mapped without activating the `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-no-filter-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-no-filter-entity-query-example.sql[]
----
====
If the filter is enabled and the filter parameter value is provided,
then Hibernate is going to apply the filtering criteria to the associated `Account` entities.
[[mapping-filter-entity-query-example]]
.Query entities mapped with `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-entity-query-example.sql[]
----
====
[IMPORTANT]
====
Filters apply to entity queries, but not to direct fetching.
Therefore, in the following example, the filter is not taken into consideration when fetching an entity from the Persistence Context.
[[mapping-filter-entity-example]]
.Fetching entities mapped with `@Filter`
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-entity-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-entity-example.sql[]
----
As you can see from the example above, contrary to an entity query, the filter does not prevent the entity from being loaded.
====
Just like with entity queries, collections can be filtered as well, but only if the filter is explicitly enabled on the currently running Hibernate `Session`.
[[mapping-no-filter-collection-query-example]]
.Traversing collections without activating the `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-no-filter-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-no-filter-collection-query-example.sql[]
----
====
When activating the `@Filter` and fetching the `accounts` collections, Hibernate is going to apply the filter condition to the associated collection entries.
[[mapping-filter-collection-query-example]]
.Traversing collections mapped with `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-collection-query-example.sql[]
----
====
[NOTE]
====
The main advantage of `@Filter` over the `@Where` clause is that the filtering criteria can be customized at runtime.
====
[WARNING]
====
It's not possible to combine the `@Filter` and `@Cache` collection annotations.
This limitation is due to ensuring consistency and because the filtering information is not stored in the second-level cache.
If caching were allowed for a currently filtered collection, then the second-level cache would store only a subset of the whole collection.
Afterward, every other Session will get the filtered collection from the cache, even if the Session-level filters have not been explicitly activated.
For this reason, the second-level collection cache is limited to storing whole collections, and not subsets.
====
[[mapping-column-filter-join-table]]
==== `@FilterJoinTable`
When using the `@Filter` annotation with collections, the filtering is done against the child entries (entities or embeddables).
However, if you have a link table between the parent entity and the child table, then you need to use the `@FilterJoinTable` to filter child entries according to some column contained in the join table.
The `@FilterJoinTable` annotation can be, therefore, applied to a unidirectional `@OneToMany` collection as illustrated in the following mapping:
[[mapping-filter-join-table-example]]
.`@FilterJoinTable` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterJoinTableTest.java[tags=mapping-filter-join-table-example]
----
====
The `firstAccounts` filter will allow us to get only the `Account` entities that have the `order_id`
(which tells the position of every entry inside the `accounts` collection)
less than a given number (e.g. `maxOrderId`).
Let's assume our database contains the following entities:
[[mapping-filter-join-table-persistence-example]]
.Persisting and fetching entities with a `@FilterJoinTable` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterJoinTableTest.java[tags=mapping-filter-join-table-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-join-table-persistence-example.sql[]
----
====
The collections can be filtered only if the associated filter is enabled on the currently running Hibernate `Session`.
[[mapping-no-filter-join-table-collection-query-example]]
.Traversing collections mapped with `@FilterJoinTable` without enabling the filter
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterJoinTableTest.java[tags=mapping-no-filter-join-table-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-no-filter-join-table-collection-query-example.sql[]
----
====
If we enable the filter and set the `maxOrderId` to `1` when fetching the `accounts` collections, Hibernate is going to apply the `@FilterJoinTable` clause filtering criteria, and we will get just
`2` `Account` entities, with the `order_id` values of `0` and `1`.
[[mapping-filter-join-table-collection-query-example]]
.Traversing collections mapped with `@FilterJoinTable`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterJoinTableTest.java[tags=mapping-filter-join-table-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-join-table-collection-query-example.sql[]
----
====
[[mapping-column-filter-sql-fragment-alias]]
==== `@Filter` with `@SqlFragmentAlias`
When using the `@Filter` annotation and working with entities that are mapped onto multiple database tables,
you will need to use the
https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/SqlFragmentAlias.html[`@SqlFragmentAlias`] annotation
if the `@Filter` defines a condition that uses predicates across multiple tables.
[[mapping-filter-sql-fragment-alias-example]]
.`@SqlFragmentAlias` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterSqlFragementAliasTest.java[tags=mapping-filter-sql-fragment-alias-example]
----
====
Now, when fetching the `Account` entities and activating the filter,
Hibernate is going to apply the right table aliases to the filter predicates:
[[mapping-filter-sql-fragment-alias-query-example]]
.Fetching a collection filtered with `@SqlFragmentAlias`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/FilterSqlFragementAliasTest.java[tags=mapping-filter-sql-fragment-alias-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-filter-sql-fragment-alias-query-example.sql[]
----
====
[[mapping-column-any]]
==== `@Any` mapping
There is one more type of property mapping.
The `@Any` mapping defines a polymorphic association to classes from multiple tables.
This type of mapping requires more than one column.
The first column contains the type of the associated entity.
The remaining columns contain the identifier.
[NOTE]
====
It is impossible to specify a foreign key constraint for this kind of association.
This is not the usual way of mapping polymorphic associations and you should use this only in special cases (e.g. audit logs, user session data, etc).
====
The `@Any` annotation describes the column holding the metadata information.
To link the value of the metadata information and an actual entity type, the `@AnyDef` and `@AnyDefs` annotations are used.
The `metaType` attribute allows the application to specify a custom type that maps database column values to persistent classes that have identifier properties of the type specified by `idType`.
You must specify the mapping from values of the `metaType` to class names.
For the next examples, consider the following `Property` class hierarchy:
[[mapping-column-any-property-example]]
.`Property` class hierarchy
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/Property.java[tags=mapping-column-any-property-example]
include::{sourcedir}/basic/any/IntegerProperty.java[tags=mapping-column-any-property-example]
include::{sourcedir}/basic/any/StringProperty.java[tags=mapping-column-any-property-example]
----
====
A `PropertyHolder` can reference any such property, and, because each `Property` belongs to a separate table, the `@Any` annotation is, therefore, required.
[[mapping-column-any-example]]
.`@Any` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/PropertyHolder.java[tags=mapping-column-any-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-any-example.sql[]
----
====
As you can see, there are two columns used to reference a `Property` instance: `property_id` and `property_type`.
The `property_id` is used to match the `id` column of either the `string_property` or `integer_property` tables,
while the `property_type` is used to match the `string_property` or the `integer_property` table.
The table resolving mapping is defined by the `metaDef` attribute which references an `@AnyMetaDef` mapping.
Although the `@AnyMetaDef` mapping could be set right next to the `@Any` annotation,
it's good practice to reuse it, therefore it makes sense to configure it on a class or package-level basis.
The `package-info.java` contains the `@AnyMetaDef` mapping:
[[mapping-column-any-meta-def-example]]
.`@Any` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/package-info.java[tags=mapping-column-any-meta-def-example]
----
====
[NOTE]
====
It is recommended to place the `@AnyMetaDef` mapping as a package metadata.
====
To see the `@Any` annotation in action, consider the next examples.
If we persist an `IntegerProperty` as well as a `StringProperty` entity, and associate
the `StringProperty` entity with a `PropertyHolder`,
Hibernate will generate the following SQL queries:
[[mapping-column-any-persist-example]]
.`@Any` mapping persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/AnyTest.java[tags=mapping-column-any-persist-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-any-persist-example.sql[]
----
====
When fetching the `PropertyHolder` entity and navigating its `property` association,
Hibernate will fetch the associated `StringProperty` entity like this:
[[mapping-column-any-query-example]]
.`@Any` mapping query example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/AnyTest.java[tags=mapping-column-any-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-any-query-example.sql[]
----
====
[[mapping-column-many-to-any]]
===== `@ManyToAny` mapping
The `@Any` mapping is useful to emulate a `@ManyToOne` association when there can be multiple target entities.
To emulate a `@OneToMany` association, the `@ManyToAny` annotation must be used.
In the following example, the `PropertyRepository` entity has a collection of `Property` entities.
The `repository_properties` link table holds the associations between `PropertyRepository` and `Property` entities.
[[mapping-column-many-to-any-example]]
.`@ManyToAny` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/PropertyRepository.java[tags=mapping-column-many-to-any-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-many-to-any-example.sql[]
----
====
To see the `@ManyToAny` annotation in action, consider the next examples.
If we persist an `IntegerProperty` as well as a `StringProperty` entity,
and associate both of them with a `PropertyRepository` parent entity,
Hibernate will generate the following SQL queries:
[[mapping-column-many-to-any-persist-example]]
.`@ManyToAny` mapping persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/ManyToAnyTest.java[tags=mapping-column-many-to-any-persist-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-many-to-any-persist-example.sql[]
----
====
When fetching the `PropertyRepository` entity and navigating its `properties` association,
Hibernate will fetch the associated `IntegerProperty` and `StringProperty` entities like this:
[[mapping-column-many-to-any-query-example]]
.`@ManyToAny` mapping query example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/any/ManyToAnyTest.java[tags=mapping-column-many-to-any-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-column-many-to-any-query-example.sql[]
----
====
[[mapping-JoinFormula]]
==== `@JoinFormula` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinFormula.html[`@JoinFormula`] annotation is used to customize the join between a child Foreign Key and a parent row Primary Key.
[[mapping-JoinFormula-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinFormulaTest.java[tags=mapping-JoinFormula-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinFormula-example.sql[]
----
====
The `country` association in the `User` entity is mapped by the country identifier provided by the `phoneNumber` property.
Considering we have the following entities:
[[mapping-JoinFormula-persistence-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinFormulaTest.java[tags=mapping-JoinFormula-persistence-example]
----
====
When fetching the `User` entities, the `country` property is mapped by the `@JoinFormula` expression:
[[mapping-JoinFormula-fetching-example]]
.`@JoinFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinFormulaTest.java[tags=mapping-JoinFormula-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinFormula-fetching-example.sql[]
----
====
Therefore, the `@JoinFormula` annotation is used to define a custom join association between the parent-child association.
[[mapping-JoinColumnOrFormula]]
==== `@JoinColumnOrFormula` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/JoinColumnOrFormula.html[`@JoinColumnOrFormula`] annotation is used to customize the join between a child Foreign Key and a parent row Primary Key when we need to take into consideration a column value as well as a `@JoinFormula`.
[[mapping-JoinColumnOrFormula-example]]
.`@JoinColumnOrFormula` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinColumnOrFormula-example.sql[]
----
====
The `country` association in the `User` entity is mapped by the `language` property value and the associated `Country` `is_default` column value.
Considering we have the following entities:
[[mapping-JoinColumnOrFormula-persistence-example]]
.`@JoinColumnOrFormula` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-persistence-example]
----
====
When fetching the `User` entities, the `country` property is mapped by the `@JoinColumnOrFormula` expression:
[[mapping-JoinColumnOrFormula-fetching-example]]
.`@JoinColumnOrFormula` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/JoinColumnOrFormulaTest.java[tags=mapping-JoinColumnOrFormula-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-JoinColumnOrFormula-fetching-example.sql[]
----
====
Therefore, the `@JoinColumnOrFormula` annotation is used to define a custom join association between the parent-child association.
[[mapping-Target]]
==== `@Target` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Target.html[`@Target`] annotation is used to specify the implementation class of a given association that is mapped via an interface.
The
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html[`@ManyToOne`],
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html[`@OneToOne`],
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html[`@OneToMany`], and
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToMany.html[`@ManyToMany`]
feature a http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html#targetEntity--[`targetEntity`] attribute to specify the actual class of the entity association when an interface is used for the mapping.
The http://docs.oracle.com/javaee/7/api/javax/persistence/ElementCollection.html[`@ElementCollection`] association has a http://docs.oracle.com/javaee/7/api/javax/persistence/ElementCollection.html#targetClass--[`targetClass`] attribute for the same purpose.
However, for simple embeddable types, there is no such construct and so you need to use the Hibernate-specific `@Target` annotation instead.
[[mapping-Target-example]]
.`@Target` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/TargetTest.java[tags=mapping-Target-example]
----
====
The `coordinates` embeddable type is mapped as the `Coordinates` interface.
However, Hibernate needs to know the actual implementation tye, which is `GPS` in this case,
hence the `@Target` annotation is used to provide this information.
Assuming we have persisted the following `City` entity:
[[mapping-Target-persist-example]]
.`@Target` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/TargetTest.java[tags=mapping-Target-persist-example]
----
====
When fetching the `City` entity, the `coordinates` property is mapped by the `@Target` expression:
[[mapping-Target-fetching-example]]
.`@Target` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/TargetTest.java[tags=mapping-Target-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/basic/mapping-Target-fetching-example.sql[]
----
====
Therefore, the `@Target` annotation is used to define a custom join association between the parent-child association.
[[mapping-Parent]]
==== `@Parent` mapping
The Hibernate-specific `@Parent` annotation allows you to reference the owner entity from within an embeddable.
[[mapping-Parent-example]]
.`@Parent` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/ParentTest.java[tags=mapping-Parent-example]
----
====
Assuming we have persisted the following `City` entity:
[[mapping-Parent-persist-example]]
.`@Parent` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/ParentTest.java[tags=mapping-Parent-persist-example]
----
====
When fetching the `City` entity, the `city` property of the embeddable type acts as a back reference to the owning parent entity:
[[mapping-Parent-fetching-example]]
.`@Parent` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/basic/ParentTest.java[tags=mapping-Parent-fetching-example]
----
====
Therefore, the `@Parent` annotation is used to define the association between an embeddable type and the owning entity.

View File

@ -197,4 +197,99 @@ This usage is covered in detail in <<chapters/domain/identifiers.adoc#identifier
[IMPORTANT]
====
Embeddable types that are used as collection entries, map keys or entity type identifiers cannot include their own collection mappings.
====
====
[[embeddable-Target]]
==== `@Target` mapping
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Target.html[`@Target`] annotation is used to specify the implementation class of a given association that is mapped via an interface.
The
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html[`@ManyToOne`],
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToOne.html[`@OneToOne`],
http://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html[`@OneToMany`], and
http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToMany.html[`@ManyToMany`]
feature a http://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html#targetEntity--[`targetEntity`] attribute to specify the actual class of the entity association when an interface is used for the mapping.
The http://docs.oracle.com/javaee/7/api/javax/persistence/ElementCollection.html[`@ElementCollection`] association has a http://docs.oracle.com/javaee/7/api/javax/persistence/ElementCollection.html#targetClass--[`targetClass`] attribute for the same purpose.
However, for simple embeddable types, there is no such construct and so you need to use the Hibernate-specific `@Target` annotation instead.
[[embeddable-Target-example]]
.`@Target` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/TargetTest.java[tags=embeddable-Target-example]
----
====
The `coordinates` embeddable type is mapped as the `Coordinates` interface.
However, Hibernate needs to know the actual implementation tye, which is `GPS` in this case,
hence the `@Target` annotation is used to provide this information.
Assuming we have persisted the following `City` entity:
[[embeddable-Target-persist-example]]
.`@Target` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/TargetTest.java[tags=embeddable-Target-persist-example]
----
====
When fetching the `City` entity, the `coordinates` property is mapped by the `@Target` expression:
[[embeddable-Target-fetching-example]]
.`@Target` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/TargetTest.java[tags=embeddable-Target-fetching-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/embeddable/embeddable-Target-fetching-example.sql[]
----
====
Therefore, the `@Target` annotation is used to define a custom join association between the parent-child association.
[[embeddable-Parent]]
==== `@Parent` mapping
The Hibernate-specific `@Parent` annotation allows you to reference the owner entity from within an embeddable.
[[embeddable-Parent-example]]
.`@Parent` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/ParentTest.java[tags=embeddable-Parent-example]
----
====
Assuming we have persisted the following `City` entity:
[[embeddable-Parent-persist-example]]
.`@Parent` persist example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/ParentTest.java[tags=embeddable-Parent-persist-example]
----
====
When fetching the `City` entity, the `city` property of the embeddable type acts as a back reference to the owning parent entity:
[[embeddable-Parent-fetching-example]]
.`@Parent` fetching example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/ParentTest.java[tags=embeddable-Parent-fetching-example]
----
====
Therefore, the `@Parent` annotation is used to define the association between an embeddable type and the owning entity.

View File

@ -232,6 +232,380 @@ load::
Each of these two methods defines an overloading variant accepting a `org.hibernate.LockOptions` argument.
Locking is discussed in a separate <<chapters/locking/Locking.adoc#locking,chapter>>.
[[pc-filtering]]
=== Filtering entities and associations
Hibernate offers two options if you want to filter entities or entity associations:
static (e.g. `@Where` and `@WhereJoinTable`):: which are defined at mapping time and
cannot change at runtime.
dynamic (e.g. `@Filter` and `@FilterJoinTable`):: which are applied and configured at runtime.
[[pc-where]]
==== `@Where`
Sometimes, you want to filter out entities or collections using custom SQL criteria.
This can be achieved using the `@Where` annotation, which can be applied to entities and collections.
[[pc-where-example]]
.`@Where` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereTest.java[tags=pc-where-example]
----
====
If the database contains the following entities:
[[pc-where-persistence-example]]
.Persisting and fetching entities with a `@Where` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereTest.java[tags=pc-where-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-where-persistence-example.sql[]
----
====
When executing an `Account` entity query, Hibernate is going to filter out all records that are not active.
[[pc-where-entity-query-example]]
.Query entities mapped with `@Where`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereTest.java[tags=pc-where-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-where-entity-query-example.sql[]
----
====
When fetching the `debitAccounts` or the `creditAccounts` collections, Hibernate is going to apply the `@Where` clause filtering criteria to the associated child entities.
[[pc-where-collection-query-example]]
.Traversing collections mapped with `@Where`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereTest.java[tags=pc-where-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-where-collection-query-example.sql[]
----
====
[[pc-where-join-table]]
==== `@WhereJoinTable`
Just like `@Where` annotation, `@WhereJoinTable` is used to filter out collections using a joined table (e.g. @ManyToMany association).
[[pc-where-join-table-example]]
.`@WhereJoinTable` mapping example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereJoinTableTest.java[tags=pc-where-join-table-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-where-join-table-example.sql[]
----
====
In the example above, the current week `Reader` entities are included in the `currentWeekReaders` collection
which uses the `@WhereJoinTable` annotation to filter the joined table rows according to the provided SQL clause.
Considering that the following two `Book_Reader` entries are added into our system:
[[pc-where-join-table-persist-example]]
.`@WhereJoinTable` test data
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereJoinTableTest.java[tags=pc-where-join-table-persist-example]
----
====
When fetching the `currentWeekReaders` collection, Hibernate is going to find one one entry:
[[pc-where-join-table-fetch-example]]
.`@WhereJoinTable` fetch example
====
[source, JAVA, indent=0]
----
include::{sourcedir}/WhereJoinTableTest.java[tags=pc-where-join-table-fetch-example]
----
====
[[pc-filter]]
==== `@Filter`
The `@Filter` annotation is another way to filter out entities or collections using custom SQL criteria.
Unlike the `@Where` annotation, `@Filter` allows you to parameterize the filter clause at runtime.
Now, considering we have the following `Account` entity:
[[pc-filter-account-example]]
.`@Filter` mapping entity-level usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-Account-example]
----
====
[NOTE]
====
Notice that the `active` property is mapped to the `active_status` column.
This mapping was done to show you that the `@Filter` condition uses a SQL condition and not a JPQL filtering predicate.
====
As already explained, we can also apply the `@Filter` annotation for collections as illustrated by the `Client` entity:
[[pc-filter-client-example]]
.`@Filter` mapping collection-level usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-Client-example]
----
====
If we persist a `Client` with three associated `Account` entities,
Hibernate will execute the following SQL statements:
[[pc-filter-persistence-example]]
.Persisting and fetching entities with a `@Filter` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-persistence-example.sql[]
----
====
By default, without explicitly enabling the filter, Hibernate is going to fetch all `Account` entities.
[[pc-no-filter-entity-query-example]]
.Query entities mapped without activating the `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-no-filter-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-no-filter-entity-query-example.sql[]
----
====
If the filter is enabled and the filter parameter value is provided,
then Hibernate is going to apply the filtering criteria to the associated `Account` entities.
[[pc-filter-entity-query-example]]
.Query entities mapped with `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-entity-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-entity-query-example.sql[]
----
====
[IMPORTANT]
====
Filters apply to entity queries, but not to direct fetching.
Therefore, in the following example, the filter is not taken into consideration when fetching an entity from the Persistence Context.
[[pc-filter-entity-example]]
.Fetching entities mapped with `@Filter`
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-entity-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-entity-example.sql[]
----
As you can see from the example above, contrary to an entity query, the filter does not prevent the entity from being loaded.
====
Just like with entity queries, collections can be filtered as well, but only if the filter is explicitly enabled on the currently running Hibernate `Session`.
[[pc-no-filter-collection-query-example]]
.Traversing collections without activating the `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-no-filter-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-no-filter-collection-query-example.sql[]
----
====
When activating the `@Filter` and fetching the `accounts` collections, Hibernate is going to apply the filter condition to the associated collection entries.
[[pc-filter-collection-query-example]]
.Traversing collections mapped with `@Filter`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterTest.java[tags=pc-filter-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-collection-query-example.sql[]
----
====
[NOTE]
====
The main advantage of `@Filter` over the `@Where` clause is that the filtering criteria can be customized at runtime.
====
[WARNING]
====
It's not possible to combine the `@Filter` and `@Cache` collection annotations.
This limitation is due to ensuring consistency and because the filtering information is not stored in the second-level cache.
If caching were allowed for a currently filtered collection, then the second-level cache would store only a subset of the whole collection.
Afterward, every other Session will get the filtered collection from the cache, even if the Session-level filters have not been explicitly activated.
For this reason, the second-level collection cache is limited to storing whole collections, and not subsets.
====
[[pc-filter-sql-fragment-alias]]
==== `@Filter` with `@SqlFragmentAlias`
When using the `@Filter` annotation and working with entities that are mapped onto multiple database tables,
you will need to use the
https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/SqlFragmentAlias.html[`@SqlFragmentAlias`] annotation
if the `@Filter` defines a condition that uses predicates across multiple tables.
[[pc-filter-sql-fragment-alias-example]]
.`@SqlFragmentAlias` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterSqlFragementAliasTest.java[tags=pc-filter-sql-fragment-alias-example]
----
====
Now, when fetching the `Account` entities and activating the filter,
Hibernate is going to apply the right table aliases to the filter predicates:
[[pc-filter-sql-fragment-alias-query-example]]
.Fetching a collection filtered with `@SqlFragmentAlias`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterSqlFragementAliasTest.java[tags=pc-filter-sql-fragment-alias-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-sql-fragment-alias-query-example.sql[]
----
====
[[pc-filter-join-table]]
==== `@FilterJoinTable`
When using the `@Filter` annotation with collections, the filtering is done against the child entries (entities or embeddables).
However, if you have a link table between the parent entity and the child table, then you need to use the `@FilterJoinTable` to filter child entries according to some column contained in the join table.
The `@FilterJoinTable` annotation can be, therefore, applied to a unidirectional `@OneToMany` collection as illustrated in the following mapping:
[[pc-filter-join-table-example]]
.`@FilterJoinTable` mapping usage
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterJoinTableTest.java[tags=pc-filter-join-table-example]
----
====
The `firstAccounts` filter will allow us to get only the `Account` entities that have the `order_id`
(which tells the position of every entry inside the `accounts` collection)
less than a given number (e.g. `maxOrderId`).
Let's assume our database contains the following entities:
[[pc-filter-join-table-persistence-example]]
.Persisting and fetching entities with a `@FilterJoinTable` mapping
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterJoinTableTest.java[tags=pc-filter-join-table-persistence-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-join-table-persistence-example.sql[]
----
====
The collections can be filtered only if the associated filter is enabled on the currently running Hibernate `Session`.
[[pc-no-filter-join-table-collection-query-example]]
.Traversing collections mapped with `@FilterJoinTable` without enabling the filter
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterJoinTableTest.java[tags=pc-no-filter-join-table-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-no-filter-join-table-collection-query-example.sql[]
----
====
If we enable the filter and set the `maxOrderId` to `1` when fetching the `accounts` collections, Hibernate is going to apply the `@FilterJoinTable` clause filtering criteria, and we will get just
`2` `Account` entities, with the `order_id` values of `0` and `1`.
[[pc-filter-join-table-collection-query-example]]
.Traversing collections mapped with `@FilterJoinTable`
====
[source, JAVA, indent=0]
----
include::{sourcedir}/FilterJoinTableTest.java[tags=pc-filter-join-table-collection-query-example]
----
[source, SQL, indent=0]
----
include::{extrasdir}/pc-filter-join-table-collection-query-example.sql[]
----
====
[[pc-managed-state]]
=== Modifying managed/persistent state

View File

@ -0,0 +1,20 @@
SELECT
c.id as id1_1_0_,
c.name as name2_1_0_
FROM
Client c
WHERE
c.id = 1
SELECT
a.id as id1_0_,
a.active_status as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE
accounts0_.active_status = true
and a.client_id = 1

View File

@ -0,0 +1,13 @@
SELECT
a.id as id1_0_0_,
a.active_status as active2_0_0_,
a.amount as amount3_0_0_,
a.client_id as client_i6_0_0_,
a.rate as rate4_0_0_,
a.account_type as account_5_0_0_,
c.id as id1_1_1_,
c.name as name2_1_1_
FROM
Account a
WHERE
a.id = 2

View File

@ -0,0 +1,11 @@
SELECT
a.id as id1_0_,
a.active_status as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE
a.active_status = true

View File

@ -0,0 +1,19 @@
SELECT
ca.Client_id as Client_i1_2_0_,
ca.accounts_id as accounts2_2_0_,
ca.order_id as order_id3_0_,
a.id as id1_0_1_,
a.amount as amount3_0_1_,
a.rate as rate4_0_1_,
a.account_type as account_5_0_1_
FROM
Client_Account ca
INNER JOIN
Account a
ON ca.accounts_id=a.id
WHERE
ca.order_id <= ?
AND ca.Client_id = ?
-- binding parameter [1] as [INTEGER] - [1]
-- binding parameter [2] as [BIGINT] - [1]

View File

@ -0,0 +1,23 @@
INSERT INTO Client (name, id)
VALUES ('John Doe', 1)
INSERT INTO Account (amount, client_id, rate, account_type, id)
VALUES (5000.0, 1, 0.0125, 'CREDIT', 1)
INSERT INTO Account (amount, client_id, rate, account_type, id)
VALUES (0.0, 1, 0.0105, 'DEBIT', 2)
INSERT INTO Account (amount, client_id, rate, account_type, id)
VALUES (250.0, 1, 0.0105, 'DEBIT', 3)
INSERT INTO Client_Account (Client_id, order_id, accounts_id)
VALUES (1, 0, 1)
INSERT INTO Client_Account (Client_id, order_id, accounts_id)
VALUES (1, 0, 1)
INSERT INTO Client_Account (Client_id, order_id, accounts_id)
VALUES (1, 1, 2)
INSERT INTO Client_Account (Client_id, order_id, accounts_id)
VALUES (1, 2, 3)

View File

@ -0,0 +1,11 @@
INSERT INTO Client (name, id)
VALUES ('John Doe', 1)
INSERT INTO Account (active_status, amount, client_id, rate, account_type, id)
VALUES (true, 5000.0, 1, 0.0125, 'CREDIT', 1)
INSERT INTO Account (active_status, amount, client_id, rate, account_type, id)
VALUES (false, 0.0, 1, 0.0105, 'DEBIT', 2)
INSERT INTO Account (active_status, amount, client_id, rate, account_type, id)
VALUES (true, 250.0, 1, 0.0105, 'DEBIT', 3)

View File

@ -0,0 +1,16 @@
select
filtersqlf0_.id as id1_0_,
filtersqlf0_.active as active2_0_,
filtersqlf0_.amount as amount3_0_,
filtersqlf0_.rate as rate4_0_,
filtersqlf0_1_.deleted as deleted1_1_
from
account filtersqlf0_
left outer join
account_details filtersqlf0_1_
on filtersqlf0_.id=filtersqlf0_1_.id
where
filtersqlf0_.active = ?
and filtersqlf0_1_.deleted = false
-- binding parameter [1] as [BOOLEAN] - [true]

View File

@ -0,0 +1,19 @@
SELECT
c.id as id1_1_0_,
c.name as name2_1_0_
FROM
Client c
WHERE
c.id = 1
SELECT
a.id as id1_0_,
a.active_status as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE
a.client_id = 1

View File

@ -0,0 +1,9 @@
SELECT
a.id as id1_0_,
a.active_status as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a

View File

@ -0,0 +1,17 @@
SELECT
ca.Client_id as Client_i1_2_0_,
ca.accounts_id as accounts2_2_0_,
ca.order_id as order_id3_0_,
a.id as id1_0_1_,
a.amount as amount3_0_1_,
a.rate as rate4_0_1_,
a.account_type as account_5_0_1_
FROM
Client_Account ca
INNER JOIN
Account a
ON ca.accounts_id=a.id
WHERE
ca.Client_id = ?
-- binding parameter [1] as [BIGINT] - [1]

View File

@ -0,0 +1,25 @@
SELECT
c.client_id as client_i6_0_0_,
c.id as id1_0_0_,
c.id as id1_0_1_,
c.active as active2_0_1_,
c.amount as amount3_0_1_,
c.client_id as client_i6_0_1_,
c.rate as rate4_0_1_,
c.account_type as account_5_0_1_
FROM
Account c
WHERE ( c.active = true and c.account_type = 'CREDIT' ) AND c.client_id = 1
SELECT
d.client_id as client_i6_0_0_,
d.id as id1_0_0_,
d.id as id1_0_1_,
d.active as active2_0_1_,
d.amount as amount3_0_1_,
d.client_id as client_i6_0_1_,
d.rate as rate4_0_1_,
d.account_type as account_5_0_1_
FROM
Account d
WHERE ( d.active = true and d.account_type = 'DEBIT' ) AND d.client_id = 1

View File

@ -0,0 +1,10 @@
SELECT
a.id as id1_0_,
a.active as active2_0_,
a.amount as amount3_0_,
a.client_id as client_i6_0_,
a.rate as rate4_0_,
a.account_type as account_5_0_
FROM
Account a
WHERE ( a.active = true )

View File

@ -0,0 +1,31 @@
create table Book (
id bigint not null,
author varchar(255),
title varchar(255),
primary key (id)
)
create table Book_Reader (
book_id bigint not null,
reader_id bigint not null
)
create table Reader (
id bigint not null,
name varchar(255),
primary key (id)
)
alter table Book_Reader
add constraint FKsscixgaa5f8lphs9bjdtpf9g
foreign key (reader_id)
references Reader
alter table Book_Reader
add constraint FKoyrwu9tnwlukd1616qhck21ra
foreign key (book_id)
references Book
alter table Book_Reader
add created_on timestamp
default current_timestamp

View File

@ -0,0 +1,11 @@
INSERT INTO Client (name, id)
VALUES ('John Doe', 1)
INSERT INTO Account (active, amount, client_id, rate, account_type, id)
VALUES (true, 5000.0, 1, 0.0125, 'CREDIT', 1)
INSERT INTO Account (active, amount, client_id, rate, account_type, id)
VALUES (false, 0.0, 1, 0.0105, 'DEBIT', 2)
INSERT INTO Account (active, amount, client_id, rate, account_type, id)
VALUES (true, 250.0, 1, 0.0105, 'DEBIT', 3)

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.associations;
import java.io.Serializable;
import java.util.Objects;
@ -41,7 +41,7 @@ protected Class<?>[] getAnnotatedClasses() {
@Test
public void testLifecycle() {
//tag::mapping-JoinColumnOrFormula-persistence-example[]
//tag::associations-JoinColumnOrFormula-persistence-example[]
Country US = new Country();
US.setId( 1 );
US.setDefault( true );
@ -75,9 +75,9 @@ public void testLifecycle() {
entityManager.persist( user2 );
} );
//end::mapping-JoinColumnOrFormula-persistence-example[]
//end::associations-JoinColumnOrFormula-persistence-example[]
//tag::mapping-JoinColumnOrFormula-fetching-example[]
//tag::associations-JoinColumnOrFormula-fetching-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
log.info( "Fetch User entities" );
@ -87,10 +87,10 @@ public void testLifecycle() {
User vlad = entityManager.find( User.class, 2L );
assertEquals( Romania, vlad.getCountry());
} );
//end::mapping-JoinColumnOrFormula-fetching-example[]
//end::associations-JoinColumnOrFormula-fetching-example[]
}
//tag::mapping-JoinColumnOrFormula-example[]
//tag::associations-JoinColumnOrFormula-example[]
@Entity(name = "User")
@Table(name = "users")
public static class User {
@ -123,7 +123,7 @@ public static class User {
//Getters and setters omitted for brevity
//end::mapping-JoinColumnOrFormula-example[]
//end::associations-JoinColumnOrFormula-example[]
public Long getId() {
return id;
}
@ -164,11 +164,11 @@ public void setCountry(Country country) {
this.country = country;
}
//tag::mapping-JoinColumnOrFormula-example[]
//tag::associations-JoinColumnOrFormula-example[]
}
//end::mapping-JoinColumnOrFormula-example[]
//end::associations-JoinColumnOrFormula-example[]
//tag::mapping-JoinColumnOrFormula-example[]
//tag::associations-JoinColumnOrFormula-example[]
@Entity(name = "Country")
@Table(name = "countries")
@ -186,7 +186,7 @@ public static class Country implements Serializable {
//Getters and setters, equals and hashCode methods omitted for brevity
//end::mapping-JoinColumnOrFormula-example[]
//end::associations-JoinColumnOrFormula-example[]
public int getId() {
return id;
@ -236,7 +236,7 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash( getId() );
}
//tag::mapping-JoinColumnOrFormula-example[]
//tag::associations-JoinColumnOrFormula-example[]
}
//end::mapping-JoinColumnOrFormula-example[]
//end::associations-JoinColumnOrFormula-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.associations;
import java.util.Objects;
import javax.persistence.Entity;
@ -40,7 +40,7 @@ protected Class<?>[] getAnnotatedClasses() {
@Test
public void testLifecycle() {
//tag::mapping-JoinFormula-persistence-example[]
//tag::associations-JoinFormula-persistence-example[]
Country US = new Country();
US.setId( 1 );
US.setName( "United States" );
@ -69,9 +69,9 @@ public void testLifecycle() {
user2.setPhoneNumber( "+40-123-4567" );
entityManager.persist( user2 );
} );
//end::mapping-JoinFormula-persistence-example[]
//end::associations-JoinFormula-persistence-example[]
//tag::mapping-JoinFormula-fetching-example[]
//tag::associations-JoinFormula-fetching-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
log.info( "Fetch User entities" );
@ -81,10 +81,10 @@ public void testLifecycle() {
User vlad = entityManager.find( User.class, 2L );
assertEquals( Romania, vlad.getCountry());
} );
//end::mapping-JoinFormula-fetching-example[]
//end::associations-JoinFormula-fetching-example[]
}
//tag::mapping-JoinFormula-example[]
//tag::associations-JoinFormula-example[]
@Entity(name = "User")
@Table(name = "users")
public static class User {
@ -104,7 +104,7 @@ public static class User {
//Getters and setters omitted for brevity
//end::mapping-JoinFormula-example[]
//end::associations-JoinFormula-example[]
public Long getId() {
return id;
}
@ -141,11 +141,11 @@ public Country getCountry() {
return country;
}
//tag::mapping-JoinFormula-example[]
//tag::associations-JoinFormula-example[]
}
//end::mapping-JoinFormula-example[]
//end::associations-JoinFormula-example[]
//tag::mapping-JoinFormula-example[]
//tag::associations-JoinFormula-example[]
@Entity(name = "Country")
@Table(name = "countries")
@ -158,7 +158,7 @@ public static class Country {
//Getters and setters, equals and hashCode methods omitted for brevity
//end::mapping-JoinFormula-example[]
//end::associations-JoinFormula-example[]
public int getId() {
return id;
@ -192,7 +192,7 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash( getId() );
}
//tag::mapping-JoinFormula-example[]
//tag::associations-JoinFormula-example[]
}
//end::mapping-JoinFormula-example[]
//end::associations-JoinFormula-example[]
}

View File

@ -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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
@ -37,7 +37,7 @@ protected String[] getAnnotatedPackages() {
public void test() {
doInHibernate( this::sessionFactory, session -> {
//tag::mapping-column-any-persist-example[]
//tag::associations-any-persist-example[]
IntegerProperty ageProperty = new IntegerProperty();
ageProperty.setId( 1L );
ageProperty.setName( "age" );
@ -57,16 +57,16 @@ public void test() {
namePropertyHolder.setProperty( nameProperty );
session.persist( namePropertyHolder );
//end::mapping-column-any-persist-example[]
//end::associations-any-persist-example[]
} );
doInHibernate( this::sessionFactory, session -> {
//tag::mapping-column-any-query-example[]
//tag::associations-any-query-example[]
PropertyHolder propertyHolder = session.get( PropertyHolder.class, 1L );
assertEquals("name", propertyHolder.getProperty().getName());
assertEquals("John Doe", propertyHolder.getProperty().getValue());
//end::mapping-column-any-query-example[]
//end::associations-any-query-example[]
} );
}

View File

@ -4,14 +4,14 @@
* 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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
//tag::mapping-column-any-property-example[]
//tag::associations-any-property-example[]
@Entity
@Table(name="integer_property")
@ -37,7 +37,7 @@ public Integer getValue() {
}
//Getters and setters omitted for brevity
//end::mapping-column-any-property-example[]
//end::associations-any-property-example[]
public Long getId() {
return id;
@ -54,7 +54,7 @@ public void setName(String name) {
public void setValue(Integer value) {
this.value = value;
}
//tag::mapping-column-any-property-example[]
//tag::associations-any-property-example[]
}
//end::mapping-column-any-property-example[]
//end::associations-any-property-example[]

View File

@ -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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
@ -38,7 +38,7 @@ protected String[] getAnnotatedPackages() {
public void test() {
doInHibernate( this::sessionFactory, session -> {
//tag::mapping-column-many-to-any-persist-example[]
//tag::associations-many-to-any-persist-example[]
IntegerProperty ageProperty = new IntegerProperty();
ageProperty.setId( 1L );
ageProperty.setName( "age" );
@ -60,11 +60,11 @@ public void test() {
propertyRepository.getProperties().add( nameProperty );
session.persist( propertyRepository );
//end::mapping-column-many-to-any-persist-example[]
//end::associations-many-to-any-persist-example[]
} );
doInHibernate( this::sessionFactory, session -> {
//tag::mapping-column-many-to-any-query-example[]
//tag::associations-many-to-any-query-example[]
PropertyRepository propertyRepository = session.get( PropertyRepository.class, 1L );
assertEquals(2, propertyRepository.getProperties().size());
@ -72,7 +72,7 @@ public void test() {
for(Property property : propertyRepository.getProperties()) {
assertNotNull( property.getValue() );
}
//end::mapping-column-many-to-any-query-example[]
//end::associations-many-to-any-query-example[]
} );
}

View File

@ -4,13 +4,13 @@
* 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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
//tag::mapping-column-any-property-example[]
//tag::associations-any-property-example[]
public interface Property<T> {
String getName();
T getValue();
}
//end::mapping-column-any-property-example[]
//end::associations-any-property-example[]

View File

@ -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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import javax.persistence.Column;
import javax.persistence.Entity;
@ -14,7 +14,7 @@
import org.hibernate.annotations.Any;
//tag::mapping-column-any-example[]
//tag::associations-any-example[]
@Entity
@Table( name = "property_holder" )
public class PropertyHolder {
@ -31,7 +31,7 @@ public class PropertyHolder {
//Getters and setters are omitted for brevity
//end::mapping-column-any-example[]
//end::associations-any-example[]
public Long getId() {
return id;
}
@ -47,6 +47,6 @@ public Property getProperty() {
public void setProperty(Property property) {
this.property = property;
}
//tag::mapping-column-any-example[]
//tag::associations-any-example[]
}
//end::mapping-column-any-example[]
//end::associations-any-example[]

View File

@ -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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import java.util.ArrayList;
import java.util.List;
@ -18,7 +18,7 @@
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.ManyToAny;
//tag::mapping-column-many-to-any-example[]
//tag::associations-many-to-any-example[]
@Entity
@Table( name = "property_repository" )
public class PropertyRepository {
@ -39,7 +39,7 @@ public class PropertyRepository {
//Getters and setters are omitted for brevity
//end::mapping-column-many-to-any-example[]
//end::associations-many-to-any-example[]
public Long getId() {
return id;
}
@ -52,6 +52,6 @@ public List<Property<?>> getProperties() {
return properties;
}
//tag::mapping-column-many-to-any-example[]
//tag::associations-many-to-any-example[]
}
//end::mapping-column-many-to-any-example[]
//end::associations-many-to-any-example[]

View File

@ -4,14 +4,14 @@
* 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.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
//tag::mapping-column-any-property-example[]
//tag::associations-any-property-example[]
@Entity
@Table(name="string_property")
@ -37,7 +37,7 @@ public String getValue() {
}
//Getters and setters omitted for brevity
//end::mapping-column-any-property-example[]
//end::associations-any-property-example[]
public Long getId() {
return id;
@ -54,6 +54,6 @@ public void setName(String name) {
public void setValue(String value) {
this.value = value;
}
//tag::mapping-column-any-property-example[]
//tag::associations-any-property-example[]
}
//end::mapping-column-any-property-example[]
//end::associations-any-property-example[]

View File

@ -6,16 +6,16 @@
*/
// $Id$
//tag::mapping-column-any-meta-def-example[]
//tag::associations-any-meta-def-example[]
@AnyMetaDef( name= "PropertyMetaDef", metaType = "string", idType = "long",
metaValues = {
@MetaValue(value = "S", targetEntity = StringProperty.class),
@MetaValue(value = "I", targetEntity = IntegerProperty.class)
}
)
package org.hibernate.userguide.mapping.basic.any;
package org.hibernate.userguide.associations.any;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.MetaValue;
//end::mapping-column-any-meta-def-example[]
//end::associations-any-meta-def-example[]

View File

@ -0,0 +1,144 @@
/*
* 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.userguide.mapping.embeddable;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.Parent;
import org.hibernate.annotations.Target;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertSame;
/**
* @author Vlad Mihalcea
*/
public class ParentTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
City.class,
};
}
@Test
public void testLifecycle() {
//tag::embeddable-Parent-persist-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
City cluj = new City();
cluj.setName( "Cluj" );
cluj.setCoordinates( new GPS( 46.77120, 23.62360 ) );
entityManager.persist( cluj );
} );
//end::embeddable-Parent-persist-example[]
//tag::embeddable-Parent-fetching-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
City cluj = entityManager.find( City.class, 1L );
assertSame( cluj, cluj.getCoordinates().getCity() );
} );
//end::embeddable-Parent-fetching-example[]
}
//tag::embeddable-Parent-example[]
@Embeddable
public static class GPS {
private double latitude;
private double longitude;
@Parent
private City city;
//Getters and setters omitted for brevity
//end::embeddable-Parent-example[]
private GPS() {
}
public GPS(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public City getCity() {
return city;
}
public void setCity(City city) {
this.city = city;
}
//tag::embeddable-Parent-example[]
}
//end::embeddable-Parent-example[]
//tag::embeddable-Parent-example[]
@Entity(name = "City")
public static class City {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
@Target( GPS.class )
private GPS coordinates;
//Getters and setters omitted for brevity
//end::embeddable-Parent-example[]
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public GPS getCoordinates() {
return coordinates;
}
public void setCoordinates(GPS coordinates) {
this.coordinates = coordinates;
}
//tag::embeddable-Parent-example[]
}
//end::embeddable-Parent-example[]
}

View File

@ -0,0 +1,131 @@
/*
* 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.userguide.mapping.embeddable;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import org.hibernate.annotations.Target;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* @author Vlad Mihalcea
*/
public class TargetTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
City.class,
};
}
@Test
public void testLifecycle() {
//tag::embeddable-Target-persist-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
City cluj = new City();
cluj.setName( "Cluj" );
cluj.setCoordinates( new GPS( 46.77120, 23.62360 ) );
entityManager.persist( cluj );
} );
//end::embeddable-Target-persist-example[]
//tag::embeddable-Target-fetching-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
City cluj = entityManager.find( City.class, 1L );
assertEquals( 46.77120, cluj.getCoordinates().x(), 0.00001 );
assertEquals( 23.62360, cluj.getCoordinates().y(), 0.00001 );
} );
//end::embeddable-Target-fetching-example[]
}
//tag::embeddable-Target-example[]
public interface Coordinates {
double x();
double y();
}
@Embeddable
public static class GPS implements Coordinates {
private double latitude;
private double longitude;
private GPS() {
}
public GPS(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
@Override
public double x() {
return latitude;
}
@Override
public double y() {
return longitude;
}
}
@Entity(name = "City")
public static class City {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
@Target( GPS.class )
private Coordinates coordinates;
//Getters and setters omitted for brevity
//end::embeddable-Target-example[]
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Coordinates getCoordinates() {
return coordinates;
}
public void setCoordinates(Coordinates coordinates) {
this.coordinates = coordinates;
}
//tag::embeddable-Target-example[]
}
//end::embeddable-Target-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.pc;
import java.util.ArrayList;
import java.util.List;
@ -47,7 +47,7 @@ protected Class<?>[] getAnnotatedClasses() {
@Test
public void testLifecycle() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::mapping-filter-join-table-persistence-example[]
//tag::pc-filter-join-table-persistence-example[]
Client client = new Client()
.setId( 1L )
.setName( "John Doe" );
@ -77,21 +77,21 @@ public void testLifecycle() {
);
entityManager.persist( client );
//end::mapping-filter-join-table-persistence-example[]
//end::pc-filter-join-table-persistence-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::mapping-no-filter-join-table-collection-query-example[]
//tag::pc-no-filter-join-table-collection-query-example[]
Client client = entityManager.find( Client.class, 1L );
assertEquals( 3, client.getAccounts().size());
//end::mapping-no-filter-join-table-collection-query-example[]
//end::pc-no-filter-join-table-collection-query-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
log.infof( "Activate filter [%s]", "firstAccounts");
//tag::mapping-filter-join-table-collection-query-example[]
//tag::pc-filter-join-table-collection-query-example[]
Client client = entityManager.find( Client.class, 1L );
entityManager
@ -100,7 +100,7 @@ public void testLifecycle() {
.setParameter( "maxOrderId", 1);
assertEquals( 2, client.getAccounts().size());
//end::mapping-filter-join-table-collection-query-example[]
//end::pc-filter-join-table-collection-query-example[]
} );
}
@ -109,7 +109,7 @@ public enum AccountType {
CREDIT
}
//tag::mapping-filter-join-table-example[]
//tag::pc-filter-join-table-example[]
@Entity(name = "Client")
@FilterDef(
name="firstAccounts",
@ -138,7 +138,7 @@ public static class Client {
private List<Account> accounts = new ArrayList<>( );
//Getters and setters omitted for brevity
//end::mapping-filter-join-table-example[]
//end::pc-filter-join-table-example[]
public Long getId() {
return id;
}
@ -160,7 +160,7 @@ public Client setName(String name) {
public List<Account> getAccounts() {
return accounts;
}
//tag::mapping-filter-join-table-example[]
//tag::pc-filter-join-table-example[]
public void addAccount(Account account) {
this.accounts.add( account );
@ -182,7 +182,7 @@ public static class Account {
private Double rate;
//Getters and setters omitted for brevity
//end::mapping-filter-join-table-example[]
//end::pc-filter-join-table-example[]
public Long getId() {
return id;
}
@ -219,7 +219,7 @@ public Account setRate(Double rate) {
return this;
}
//tag::mapping-filter-join-table-example[]
//tag::pc-filter-join-table-example[]
}
//end::mapping-filter-join-table-example[]
//end::pc-filter-join-table-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.pc;
import java.sql.Timestamp;
import java.util.ArrayList;
@ -81,7 +81,7 @@ public void testLifecycle() {
doInJPA( this::entityManagerFactory, entityManager -> {
log.infof( "Activate filter [%s]", "activeAccount");
//tag::mapping-filter-sql-fragment-alias-query-example[]
//tag::pc-filter-sql-fragment-alias-query-example[]
entityManager
.unwrap( Session.class )
.enableFilter( "activeAccount" )
@ -90,12 +90,12 @@ public void testLifecycle() {
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
//end::mapping-filter-sql-fragment-alias-query-example[]
//end::pc-filter-sql-fragment-alias-query-example[]
assertEquals( 2, accounts.size());
} );
}
//tag::mapping-filter-sql-fragment-alias-example[]
//tag::pc-filter-sql-fragment-alias-example[]
@Entity(name = "Account")
@Table(name = "account")
@SecondaryTable(
@ -135,7 +135,7 @@ public static class Account {
//Getters and setters omitted for brevity
//end::mapping-filter-sql-fragment-alias-example[]
//end::pc-filter-sql-fragment-alias-example[]
public Long getId() {
return id;
}
@ -168,7 +168,7 @@ public void setActive(boolean active) {
this.active = active;
}
//tag::mapping-filter-sql-fragment-alias-example[]
//tag::pc-filter-sql-fragment-alias-example[]
}
//end::mapping-filter-sql-fragment-alias-example[]
//end::pc-filter-sql-fragment-alias-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.pc;
import java.util.ArrayList;
import java.util.List;
@ -53,7 +53,7 @@ protected Class<?>[] getAnnotatedClasses() {
public void testLifecycle() {
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::mapping-filter-persistence-example[]
//tag::pc-filter-persistence-example[]
Client client = new Client()
.setId( 1L )
.setName( "John Doe" );
@ -86,7 +86,7 @@ public void testLifecycle() {
);
entityManager.persist( client );
//end::mapping-filter-persistence-example[]
//end::pc-filter-persistence-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
@ -129,7 +129,7 @@ public void testLifecycle() {
doInJPA( this::entityManagerFactory, entityManager -> {
log.infof( "Activate filter [%s]", "activeAccount");
//tag::mapping-filter-entity-example[]
//tag::pc-filter-entity-example[]
entityManager
.unwrap( Session.class )
.enableFilter( "activeAccount" )
@ -138,22 +138,22 @@ public void testLifecycle() {
Account account = entityManager.find( Account.class, 2L );
assertFalse( account.isActive() );
//end::mapping-filter-entity-example[]
//end::pc-filter-entity-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::mapping-no-filter-entity-query-example[]
//tag::pc-no-filter-entity-query-example[]
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
assertEquals( 3, accounts.size());
//end::mapping-no-filter-entity-query-example[]
//end::pc-no-filter-entity-query-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
log.infof( "Activate filter [%s]", "activeAccount");
//tag::mapping-filter-entity-query-example[]
//tag::pc-filter-entity-query-example[]
entityManager
.unwrap( Session.class )
.enableFilter( "activeAccount" )
@ -164,21 +164,21 @@ public void testLifecycle() {
.getResultList();
assertEquals( 2, accounts.size());
//end::mapping-filter-entity-query-example[]
//end::pc-filter-entity-query-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
//tag::mapping-no-filter-collection-query-example[]
//tag::pc-no-filter-collection-query-example[]
Client client = entityManager.find( Client.class, 1L );
assertEquals( 3, client.getAccounts().size() );
//end::mapping-no-filter-collection-query-example[]
//end::pc-no-filter-collection-query-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
log.infof( "Activate filter [%s]", "activeAccount");
//tag::mapping-filter-collection-query-example[]
//tag::pc-filter-collection-query-example[]
entityManager
.unwrap( Session.class )
.enableFilter( "activeAccount" )
@ -187,7 +187,7 @@ public void testLifecycle() {
Client client = entityManager.find( Client.class, 1L );
assertEquals( 2, client.getAccounts().size() );
//end::mapping-filter-collection-query-example[]
//end::pc-filter-collection-query-example[]
} );
}
@ -196,7 +196,7 @@ public enum AccountType {
CREDIT
}
//tag::mapping-filter-Client-example[]
//tag::pc-filter-Client-example[]
@Entity(name = "Client")
public static class Client {
@ -216,7 +216,7 @@ public static class Client {
private List<Account> accounts = new ArrayList<>( );
//Getters and setters omitted for brevity
//end::mapping-filter-Client-example[]
//end::pc-filter-Client-example[]
public Long getId() {
return id;
}
@ -238,16 +238,16 @@ public Client setName(String name) {
public List<Account> getAccounts() {
return accounts;
}
//tag::mapping-filter-Client-example[]
//tag::pc-filter-Client-example[]
public void addAccount(Account account) {
account.setClient( this );
this.accounts.add( account );
}
}
//end::mapping-filter-Client-example[]
//end::pc-filter-Client-example[]
//tag::mapping-filter-Account-example[]
//tag::pc-filter-Account-example[]
@Entity(name = "Account")
@FilterDef(
name="activeAccount",
@ -280,7 +280,7 @@ public static class Account {
private boolean active;
//Getters and setters omitted for brevity
//end::mapping-filter-Account-example[]
//end::pc-filter-Account-example[]
public Long getId() {
return id;
}
@ -335,7 +335,7 @@ public Account setActive(boolean active) {
return this;
}
//tag::mapping-filter-Account-example[]
//tag::pc-filter-Account-example[]
}
//end::mapping-filter-Account-example[]
//end::pc-filter-Account-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.pc;
import java.sql.Statement;
import java.util.ArrayList;
@ -42,7 +42,7 @@ protected Class<?>[] getAnnotatedClasses() {
@Test
public void testLifecycle() {
//tag::mapping-where-persistence-example[]
//tag::pc-where-persistence-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).doWork( connection -> {
@ -53,7 +53,7 @@ public void testLifecycle() {
}
} );
//tag::mapping-where-join-table-persist-example[]
//tag::pc-where-join-table-persist-example[]
Book book = new Book();
book.setId( 1L );
book.setTitle( "High-Performance Java Persistence" );
@ -69,13 +69,13 @@ public void testLifecycle() {
reader2.setId( 2L );
reader2.setName( "John Doe Jr." );
entityManager.persist( reader2 );
//end::mapping-where-join-table-persist-example[]
//end::pc-where-join-table-persist-example[]
} );
doInJPA( this::entityManagerFactory, entityManager -> {
entityManager.unwrap( Session.class ).doWork( connection -> {
try(Statement statement = connection.createStatement()) {
//tag::mapping-where-join-table-persist-example[]
//tag::pc-where-join-table-persist-example[]
statement.executeUpdate(
"INSERT INTO Book_Reader " +
@ -89,18 +89,18 @@ public void testLifecycle() {
"VALUES " +
" (1, 2, DATEADD( 'DAY', -10, CURRENT_TIMESTAMP() )) "
);
//end::mapping-where-join-table-persist-example[]
//end::pc-where-join-table-persist-example[]
}}
);
//tag::mapping-where-join-table-fetch-example[]
//tag::pc-where-join-table-fetch-example[]
Book book = entityManager.find( Book.class, 1L );
assertEquals( 1, book.getCurrentWeekReaders().size() );
//end::mapping-where-join-table-fetch-example[]
//end::pc-where-join-table-fetch-example[]
} );
}
//tag::mapping-where-join-table-example[]
//tag::pc-where-join-table-example[]
@Entity(name = "Book")
public static class Book {
@ -122,7 +122,7 @@ public static class Book {
//Getters and setters omitted for brevity
//end::mapping-where-join-table-example[]
//end::pc-where-join-table-example[]
public Long getId() {
return id;
}
@ -151,7 +151,7 @@ public List<Reader> getCurrentWeekReaders() {
return currentWeekReaders;
}
//tag::mapping-where-join-table-example[]
//tag::pc-where-join-table-example[]
}
@Entity(name = "Reader")
@ -164,7 +164,7 @@ public static class Reader {
//Getters and setters omitted for brevity
//end::mapping-where-join-table-example[]
//end::pc-where-join-table-example[]
public Long getId() {
return id;
@ -181,7 +181,7 @@ public String getName() {
public void setName(String name) {
this.name = name;
}
//tag::mapping-where-join-table-example[]
//tag::pc-where-join-table-example[]
}
//end::mapping-where-join-table-example[]
//end::pc-where-join-table-example[]
}

View File

@ -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.userguide.mapping.basic;
package org.hibernate.userguide.pc;
import java.util.ArrayList;
import java.util.List;
@ -39,7 +39,7 @@ protected Class<?>[] getAnnotatedClasses() {
@Test
public void testLifecycle() {
//tag::mapping-where-persistence-example[]
//tag::pc-where-persistence-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
Client client = new Client();
@ -77,28 +77,28 @@ public void testLifecycle() {
client.getDebitAccounts().add( account3 );
entityManager.persist( account3 );
} );
//end::mapping-where-persistence-example[]
//end::pc-where-persistence-example[]
//tag::mapping-where-entity-query-example[]
//tag::pc-where-entity-query-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
List<Account> accounts = entityManager.createQuery(
"select a from Account a", Account.class)
.getResultList();
assertEquals( 2, accounts.size());
} );
//end::mapping-where-entity-query-example[]
//end::pc-where-entity-query-example[]
//tag::mapping-where-collection-query-example[]
//tag::pc-where-collection-query-example[]
doInJPA( this::entityManagerFactory, entityManager -> {
Client client = entityManager.find( Client.class, 1L );
assertEquals( 1, client.getCreditAccounts().size() );
assertEquals( 1, client.getDebitAccounts().size() );
} );
//end::mapping-where-collection-query-example[]
//end::pc-where-collection-query-example[]
}
//tag::mapping-where-example[]
//tag::pc-where-example[]
public enum AccountType {
DEBIT,
CREDIT
@ -122,7 +122,7 @@ public static class Client {
//Getters and setters omitted for brevity
//end::mapping-where-example[]
//end::pc-where-example[]
public Long getId() {
return id;
}
@ -146,7 +146,7 @@ public List<Account> getDebitAccounts() {
public List<Account> getCreditAccounts() {
return creditAccounts;
}
//tag::mapping-where-example[]
//tag::pc-where-example[]
}
@Entity(name = "Account")
@ -171,7 +171,7 @@ public static class Account {
//Getters and setters omitted for brevity
//end::mapping-where-example[]
//end::pc-where-example[]
public Long getId() {
return id;
}
@ -220,7 +220,7 @@ public void setActive(boolean active) {
this.active = active;
}
//tag::mapping-where-example[]
//tag::pc-where-example[]
}
//end::mapping-where-example[]
//end::pc-where-example[]
}