From 88fda0598c41eba70f9bb31bc733878ee8081bc4 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Wed, 11 Jul 2018 17:42:05 +0300 Subject: [PATCH] HHH-12349 - User Guide documentation for @Filter is too verbose --- .../chapters/domain/basic_types.adoc | 94 +++- ...apping-filter-collection-query-example.sql | 26 +- .../basic/mapping-filter-entity-example.sql | 7 +- .../mapping-filter-entity-query-example.sql | 16 +- ...er-join-table-collection-query-example.sql | 22 - ...-filter-join-table-persistence-example.sql | 12 +- .../mapping-filter-persistence-example.sql | 6 +- ...ing-no-filter-collection-query-example.sql | 19 + ...mapping-no-filter-entity-query-example.sql | 9 + ...er-join-table-collection-query-example.sql | 17 + .../mapping/basic/FilterJoinTableTest.java | 291 +++++------ .../userguide/mapping/basic/FilterTest.java | 453 ++++++++++-------- 12 files changed, 538 insertions(+), 434 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-collection-query-example.sql create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-entity-query-example.sql create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-join-table-collection-query-example.sql diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index aeae05bee8..f3e5ada847 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -1768,19 +1768,40 @@ include::{sourcedir}/basic/WhereJoinTableTest.java[tags=mapping-where-join-table [[mapping-column-filter]] ==== `@Filter` -The `@Filter` annotation is another way to filter out entities or collections using custom SQL criteria, for both entities and collections. +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. -[[mapping-filter-example]] -.`@Filter` mapping usage +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-example] +include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-Account-example] ---- ==== -If the database contains the following entities: +[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 criteria. +==== + +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 @@ -1797,6 +1818,21 @@ 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. @@ -1817,6 +1853,7 @@ 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]] @@ -1835,7 +1872,22 @@ As you can see from the example above, contrary to an entity query, the filter d ==== 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`. -This way, when fetching the `accounts` collections, Hibernate is going to apply the `@Filter` clause filtering criteria to the associated collection entries. + +[[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` @@ -1861,7 +1913,7 @@ The main advantage of `@Filter` over the `@Where` clause is that the filtering c 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 was allowed for a currently filtered collection, then the second-level cache would store only a subset of the whole collection. +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. @@ -1873,7 +1925,7 @@ For this reason, the second-level collection cache is limited to storing whole c 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 illustrate din the following mapping: +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 @@ -1884,7 +1936,11 @@ include::{sourcedir}/basic/FilterJoinTableTest.java[tags=mapping-filter-join-tab ---- ==== -If the database contains the following entities: +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 @@ -1900,8 +1956,24 @@ include::{extrasdir}/basic/mapping-filter-join-table-persistence-example.sql[] ---- ==== -The collections can be filtered if the associated filter is enabled on the currently running Hibernate `Session`. -This way, when fetching the `accounts` collections, Hibernate is going to apply the `@FilterJoinTable` clause filtering criteria to the associated collection entries. +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` diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-collection-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-collection-query-example.sql index d3d216ce8d..5282632d41 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-collection-query-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-collection-query-example.sql @@ -1,25 +1,3 @@ -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 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 - --- Activate filter [activeAccount] - SELECT c.id as id1_1_0_, c.name as name2_1_0_ @@ -30,7 +8,7 @@ WHERE SELECT a.id as id1_0_, - a.active as active2_0_, + a.active_status as active2_0_, a.amount as amount3_0_, a.client_id as client_i6_0_, a.rate as rate4_0_, @@ -38,5 +16,5 @@ SELECT FROM Account a WHERE - accounts0_.active = true + accounts0_.active_status = true and a.client_id = 1 \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-example.sql index f3d4d61627..aeb9bb001e 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-example.sql @@ -1,6 +1,6 @@ SELECT a.id as id1_0_0_, - a.active as active2_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_, @@ -8,9 +8,6 @@ SELECT c.id as id1_1_1_, c.name as name2_1_1_ FROM - Account a -LEFT OUTER JOIN - Client c - ON a.client_id=c.id + Account a WHERE a.id = 2 \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-query-example.sql index 88c17423eb..5bcf7e0c35 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-query-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-entity-query-example.sql @@ -1,18 +1,6 @@ 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 - --- Activate filter [activeAccount] - -SELECT - a.id as id1_0_, - a.active as active2_0_, + a.active_status as active2_0_, a.amount as amount3_0_, a.client_id as client_i6_0_, a.rate as rate4_0_, @@ -20,4 +8,4 @@ SELECT FROM Account a WHERE - a.active = true \ No newline at end of file + a.active_status = true \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-collection-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-collection-query-example.sql index f6abfd3ec9..80226c2f50 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-collection-query-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-collection-query-example.sql @@ -3,7 +3,6 @@ SELECT ca.accounts_id as accounts2_2_0_, ca.order_id as order_id3_0_, a.id as id1_0_1_, - a.active as active2_0_1_, a.amount as amount3_0_1_, a.rate as rate4_0_1_, a.account_type as account_5_0_1_ @@ -12,27 +11,6 @@ FROM INNER JOIN Account a ON ca.accounts_id=a.id -WHERE - ca.Client_id = ? - --- binding parameter [1] as [BIGINT] - [1] - --- Activate filter [firstAccounts] - -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.active as active2_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 = ? diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-persistence-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-persistence-example.sql index e9a785d308..6bf698e00b 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-persistence-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-join-table-persistence-example.sql @@ -1,14 +1,14 @@ 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 (amount, client_id, rate, account_type, id) +VALUES (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 (amount, client_id, rate, account_type, id) +VALUES (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) +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) diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-persistence-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-persistence-example.sql index 2f4abf9d66..750c9f4f70 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-persistence-example.sql +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-filter-persistence-example.sql @@ -1,11 +1,11 @@ INSERT INTO Client (name, id) VALUES ('John Doe', 1) -INSERT INTO Account (active, amount, client_id, rate, account_type, id) +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, amount, client_id, rate, account_type, id) +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, amount, client_id, rate, account_type, id) +INSERT INTO Account (active_status, amount, client_id, rate, account_type, id) VALUES (true, 250.0, 1, 0.0105, 'DEBIT', 3) \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-collection-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-collection-query-example.sql new file mode 100644 index 0000000000..d80b60f607 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-collection-query-example.sql @@ -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 \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-entity-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-entity-query-example.sql new file mode 100644 index 0000000000..4d6dbc7655 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-entity-query-example.sql @@ -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 \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-join-table-collection-query-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-join-table-collection-query-example.sql new file mode 100644 index 0000000000..ab44fcf581 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/mapping-no-filter-join-table-collection-query-example.sql @@ -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] \ No newline at end of file diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterJoinTableTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterJoinTableTest.java index bafed596f0..83c3466bcf 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterJoinTableTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterJoinTableTest.java @@ -8,6 +8,7 @@ package org.hibernate.userguide.mapping.basic; import java.util.ArrayList; import java.util.List; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; @@ -35,180 +36,190 @@ import static org.junit.Assert.assertEquals; */ public class FilterJoinTableTest extends BaseEntityManagerFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Client.class, - Account.class - }; - } + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Client.class, + Account.class + }; + } - @Test - public void testLifecycle() { - //tag::mapping-filter-join-table-persistence-example[] - doInJPA( this::entityManagerFactory, entityManager -> { + @Test + public void testLifecycle() { + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::mapping-filter-join-table-persistence-example[] + Client client = new Client() + .setId( 1L ) + .setName( "John Doe" ); - Client client = new Client(); - client.setId( 1L ); - client.setName( "John Doe" ); - entityManager.persist( client ); + client.addAccount( + new Account() + .setId( 1L ) + .setType( AccountType.CREDIT ) + .setAmount( 5000d ) + .setRate( 1.25 / 100 ) + ); - Account account1 = new Account( ); - account1.setId( 1L ); - account1.setType( AccountType.CREDIT ); - account1.setAmount( 5000d ); - account1.setRate( 1.25 / 100 ); - account1.setActive( true ); - client.getAccounts().add( account1 ); - entityManager.persist( account1 ); + client.addAccount( + new Account() + .setId( 2L ) + .setType( AccountType.DEBIT ) + .setAmount( 0d ) + .setRate( 1.05 / 100 ) + ); - Account account2 = new Account( ); - account2.setId( 2L ); - account2.setType( AccountType.DEBIT ); - account2.setAmount( 0d ); - account2.setRate( 1.05 / 100 ); - account2.setActive( false ); - client.getAccounts().add( account2 ); - entityManager.persist( account2 ); + client.addAccount( + new Account() + .setType( AccountType.DEBIT ) + .setId( 3L ) + .setAmount( 250d ) + .setRate( 1.05 / 100 ) + ); - Account account3 = new Account( ); - account3.setType( AccountType.DEBIT ); - account3.setId( 3L ); - account3.setAmount( 250d ); - account3.setRate( 1.05 / 100 ); - account3.setActive( true ); - client.getAccounts().add( account3 ); - entityManager.persist( account3 ); - } ); - //end::mapping-filter-join-table-persistence-example[] + entityManager.persist( client ); + //end::mapping-filter-join-table-persistence-example[] + } ); - //tag::mapping-filter-join-table-collection-query-example[] - doInJPA( this::entityManagerFactory, entityManager -> { - Client client = entityManager.find( Client.class, 1L ); - assertEquals( 3, client.getAccounts().size()); - } ); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::mapping-no-filter-join-table-collection-query-example[] + Client client = entityManager.find( Client.class, 1L ); - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "firstAccounts"); + assertEquals( 3, client.getAccounts().size()); + //end::mapping-no-filter-join-table-collection-query-example[] + } ); - Client client = entityManager.find( Client.class, 1L ); + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "firstAccounts"); - entityManager - .unwrap( Session.class ) - .enableFilter( "firstAccounts" ) - .setParameter( "maxOrderId", 1); + //tag::mapping-filter-join-table-collection-query-example[] + Client client = entityManager.find( Client.class, 1L ); - assertEquals( 2, client.getAccounts().size()); - } ); - //end::mapping-filter-join-table-collection-query-example[] - } + entityManager + .unwrap( Session.class ) + .enableFilter( "firstAccounts" ) + .setParameter( "maxOrderId", 1); - //tag::mapping-filter-join-table-example[] - public enum AccountType { - DEBIT, - CREDIT - } + assertEquals( 2, client.getAccounts().size()); + //end::mapping-filter-join-table-collection-query-example[] + } ); + } - @Entity(name = "Client") - @FilterDef(name="firstAccounts", parameters=@ParamDef( name="maxOrderId", type="int" ) ) - @Filter(name="firstAccounts", condition="order_id <= :maxOrderId") - public static class Client { + public enum AccountType { + DEBIT, + CREDIT + } - @Id - private Long id; + //tag::mapping-filter-join-table-example[] + @Entity(name = "Client") + @FilterDef( + name="firstAccounts", + parameters=@ParamDef( + name="maxOrderId", + type="int" + ) + ) + @Filter( + name="firstAccounts", + condition="order_id <= :maxOrderId" + ) + public static class Client { - private String name; + @Id + private Long id; - @OneToMany - @OrderColumn(name = "order_id") - @FilterJoinTable(name="firstAccounts", condition="order_id <= :maxOrderId") - private List accounts = new ArrayList<>( ); + private String name; - //Getters and setters omitted for brevity + @OneToMany(cascade = CascadeType.ALL) + @OrderColumn(name = "order_id") + @FilterJoinTable( + name="firstAccounts", + condition="order_id <= :maxOrderId" + ) + private List accounts = new ArrayList<>( ); - //end::mapping-filter-join-table-example[] - public Long getId() { - return id; - } + //Getters and setters omitted for brevity + //end::mapping-filter-join-table-example[] + public Long getId() { + return id; + } - public void setId(Long id) { - this.id = id; - } + public Client setId(Long id) { + this.id = id; + return this; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public void setName(String name) { - this.name = name; - } + public Client setName(String name) { + this.name = name; + return this; + } - public List getAccounts() { - return accounts; - } - //tag::mapping-filter-join-table-example[] - } + public List getAccounts() { + return accounts; + } + //tag::mapping-filter-join-table-example[] - @Entity(name = "Account") - public static class Account { + public void addAccount(Account account) { + this.accounts.add( account ); + } + } - @Id - private Long id; + @Entity(name = "Account") + public static class Account { - @Column(name = "account_type") - @Enumerated(EnumType.STRING) - private AccountType type; + @Id + private Long id; - private Double amount; + @Column(name = "account_type") + @Enumerated(EnumType.STRING) + private AccountType type; - private Double rate; + private Double amount; - private boolean active; + private Double rate; - //Getters and setters omitted for brevity + //Getters and setters omitted for brevity + //end::mapping-filter-join-table-example[] + public Long getId() { + return id; + } - //end::mapping-filter-join-table-example[] - public Long getId() { - return id; - } + public Account setId(Long id) { + this.id = id; + return this; + } - public void setId(Long id) { - this.id = id; - } + public AccountType getType() { + return type; + } - public AccountType getType() { - return type; - } + public Account setType(AccountType type) { + this.type = type; + return this; + } - public void setType(AccountType type) { - this.type = type; - } + public Double getAmount() { + return amount; + } - public Double getAmount() { - return amount; - } + public Account setAmount(Double amount) { + this.amount = amount; + return this; + } - public void setAmount(Double amount) { - this.amount = amount; - } + public Double getRate() { + return rate; + } - public Double getRate() { - return rate; - } + public Account setRate(Double rate) { + this.rate = rate; + return this; + } - public void setRate(Double rate) { - this.rate = rate; - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - } - - //tag::mapping-filter-join-table-example[] - } - //end::mapping-filter-join-table-example[] + //tag::mapping-filter-join-table-example[] + } + //end::mapping-filter-join-table-example[] } diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterTest.java index b438062ba4..f678989df3 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/FilterTest.java @@ -8,10 +8,12 @@ package org.hibernate.userguide.mapping.basic; import java.util.ArrayList; import java.util.List; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.EnumType; import javax.persistence.Enumerated; +import javax.persistence.FetchType; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.NoResultException; @@ -39,268 +41,301 @@ import static org.junit.Assert.assertNull; */ public class FilterTest extends BaseEntityManagerFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Client.class, - Account.class - }; - } + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Client.class, + Account.class + }; + } - @Test - public void testLifecycle() { - //tag::mapping-filter-persistence-example[] - doInJPA( this::entityManagerFactory, entityManager -> { + @Test + public void testLifecycle() { + doInJPA( this::entityManagerFactory, entityManager -> { - Client client = new Client(); - client.setId( 1L ); - client.setName( "John Doe" ); - entityManager.persist( client ); + //tag::mapping-filter-persistence-example[] + Client client = new Client() + .setId( 1L ) + .setName( "John Doe" ); - Account account1 = new Account( ); - account1.setId( 1L ); - account1.setType( AccountType.CREDIT ); - account1.setAmount( 5000d ); - account1.setRate( 1.25 / 100 ); - account1.setActive( true ); - account1.setClient( client ); - client.getAccounts().add( account1 ); - entityManager.persist( account1 ); + client.addAccount( + new Account() + .setId( 1L ) + .setType( AccountType.CREDIT ) + .setAmount( 5000d ) + .setRate( 1.25 / 100 ) + .setActive( true ) + ); - Account account2 = new Account( ); - account2.setId( 2L ); - account2.setType( AccountType.DEBIT ); - account2.setAmount( 0d ); - account2.setRate( 1.05 / 100 ); - account2.setActive( false ); - account2.setClient( client ); - client.getAccounts().add( account2 ); - entityManager.persist( account2 ); + client.addAccount( + new Account() + .setId( 2L ) + .setType( AccountType.DEBIT ) + .setAmount( 0d ) + .setRate( 1.05 / 100 ) + .setActive( false ) + ); - Account account3 = new Account( ); - account3.setType( AccountType.DEBIT ); - account3.setId( 3L ); - account3.setAmount( 250d ); - account3.setRate( 1.05 / 100 ); - account3.setActive( true ); - account3.setClient( client ); - client.getAccounts().add( account3 ); - entityManager.persist( account3 ); - } ); - //end::mapping-filter-persistence-example[] + client.addAccount( + new Account() + .setType( AccountType.DEBIT ) + .setId( 3L ) + .setAmount( 250d ) + .setRate( 1.05 / 100 ) + .setActive( true ) + ); - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "activeAccount"); + entityManager.persist( client ); + //end::mapping-filter-persistence-example[] + } ); - entityManager - .unwrap( Session.class ) - .enableFilter( "activeAccount" ) - .setParameter( "active", true); + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "activeAccount"); - Account account1 = entityManager.find( Account.class, 1L ); - Account account2 = entityManager.find( Account.class, 2L ); + entityManager + .unwrap( Session.class ) + .enableFilter( "activeAccount" ) + .setParameter( "active", true); - assertNotNull( account1 ); - assertNotNull( account2 ); - } ); + Account account1 = entityManager.find( Account.class, 1L ); + Account account2 = entityManager.find( Account.class, 2L ); - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "activeAccount"); + assertNotNull( account1 ); + assertNotNull( account2 ); + } ); - entityManager - .unwrap( Session.class ) - .enableFilter( "activeAccount" ) - .setParameter( "active", true); + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "activeAccount"); - Account account1 = entityManager.createQuery( - "select a from Account a where a.id = :id", Account.class) - .setParameter( "id", 1L ) - .getSingleResult(); - assertNotNull( account1 ); - try { - Account account2 = entityManager.createQuery( - "select a from Account a where a.id = :id", Account.class) - .setParameter( "id", 2L ) - .getSingleResult(); - } - catch (NoResultException expected) { - expected.fillInStackTrace(); - } - } ); + entityManager + .unwrap( Session.class ) + .enableFilter( "activeAccount" ) + .setParameter( "active", true); - //tag::mapping-filter-entity-example[] - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "activeAccount"); + Account account1 = entityManager.createQuery( + "select a from Account a where a.id = :id", Account.class) + .setParameter( "id", 1L ) + .getSingleResult(); + assertNotNull( account1 ); + try { + Account account2 = entityManager.createQuery( + "select a from Account a where a.id = :id", Account.class) + .setParameter( "id", 2L ) + .getSingleResult(); + } + catch (NoResultException expected) { + } + } ); - entityManager - .unwrap( Session.class ) - .enableFilter( "activeAccount" ) - .setParameter( "active", true); + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "activeAccount"); + //tag::mapping-filter-entity-example[] + entityManager + .unwrap( Session.class ) + .enableFilter( "activeAccount" ) + .setParameter( "active", true); - Account account = entityManager.find( Account.class, 2L ); - assertFalse( account.isActive() ); - } ); - //end::mapping-filter-entity-example[] + Account account = entityManager.find( Account.class, 2L ); - // tag::mapping-filter-entity-query-example[] - doInJPA( this::entityManagerFactory, entityManager -> { - List accounts = entityManager.createQuery( - "select a from Account a", Account.class) - .getResultList(); - assertEquals( 3, accounts.size()); - } ); + assertFalse( account.isActive() ); + //end::mapping-filter-entity-example[] + } ); - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "activeAccount"); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::mapping-no-filter-entity-query-example[] + List accounts = entityManager.createQuery( + "select a from Account a", Account.class) + .getResultList(); - entityManager - .unwrap( Session.class ) - .enableFilter( "activeAccount" ) - .setParameter( "active", true); + assertEquals( 3, accounts.size()); + //end::mapping-no-filter-entity-query-example[] + } ); - List accounts = entityManager.createQuery( - "select a from Account a", Account.class) - .getResultList(); - assertEquals( 2, accounts.size()); - } ); - //end::mapping-filter-entity-query-example[] + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "activeAccount"); + //tag::mapping-filter-entity-query-example[] + entityManager + .unwrap( Session.class ) + .enableFilter( "activeAccount" ) + .setParameter( "active", true); - //tag::mapping-filter-collection-query-example[] - doInJPA( this::entityManagerFactory, entityManager -> { - Client client = entityManager.find( Client.class, 1L ); - assertEquals( 3, client.getAccounts().size() ); - } ); + List accounts = entityManager.createQuery( + "select a from Account a", Account.class) + .getResultList(); - doInJPA( this::entityManagerFactory, entityManager -> { - log.infof( "Activate filter [%s]", "activeAccount"); + assertEquals( 2, accounts.size()); + //end::mapping-filter-entity-query-example[] + } ); - entityManager - .unwrap( Session.class ) - .enableFilter( "activeAccount" ) - .setParameter( "active", true); + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::mapping-no-filter-collection-query-example[] + Client client = entityManager.find( Client.class, 1L ); - Client client = entityManager.find( Client.class, 1L ); - assertEquals( 2, client.getAccounts().size() ); - } ); - //end::mapping-filter-collection-query-example[] - } + assertEquals( 3, client.getAccounts().size() ); + //end::mapping-no-filter-collection-query-example[] + } ); - //tag::mapping-filter-example[] - public enum AccountType { - DEBIT, - CREDIT - } + doInJPA( this::entityManagerFactory, entityManager -> { + log.infof( "Activate filter [%s]", "activeAccount"); - @Entity(name = "Client") - public static class Client { + //tag::mapping-filter-collection-query-example[] + entityManager + .unwrap( Session.class ) + .enableFilter( "activeAccount" ) + .setParameter( "active", true); - @Id - private Long id; + Client client = entityManager.find( Client.class, 1L ); - private String name; + assertEquals( 2, client.getAccounts().size() ); + //end::mapping-filter-collection-query-example[] + } ); + } - @OneToMany(mappedBy = "client") - @Filter(name="activeAccount", condition="active = :active") - private List accounts = new ArrayList<>( ); + public enum AccountType { + DEBIT, + CREDIT + } - //Getters and setters omitted for brevity + //tag::mapping-filter-Client-example[] + @Entity(name = "Client") + public static class Client { - //end::mapping-filter-example[] - public Long getId() { - return id; - } + @Id + private Long id; - public void setId(Long id) { - this.id = id; - } + private String name; - public String getName() { - return name; - } + @OneToMany( + mappedBy = "client", + cascade = CascadeType.ALL + ) + @Filter( + name="activeAccount", + condition="active_status = :active" + ) + private List accounts = new ArrayList<>( ); - public void setName(String name) { - this.name = name; - } + //Getters and setters omitted for brevity + //end::mapping-filter-Client-example[] + public Long getId() { + return id; + } - public List getAccounts() { - return accounts; - } - //tag::mapping-filter-example[] - } + public Client setId(Long id) { + this.id = id; + return this; + } - @Entity(name = "Account") - @FilterDef(name="activeAccount", parameters=@ParamDef( name="active", type="boolean" ) ) - @Filter(name="activeAccount", condition="active = :active") - public static class Account { + public String getName() { + return name; + } - @Id - private Long id; + public Client setName(String name) { + this.name = name; + return this; + } - @ManyToOne - private Client client; + public List getAccounts() { + return accounts; + } + //tag::mapping-filter-Client-example[] - @Column(name = "account_type") - @Enumerated(EnumType.STRING) - private AccountType type; + public void addAccount(Account account) { + account.setClient( this ); + this.accounts.add( account ); + } + } + //end::mapping-filter-Client-example[] - private Double amount; + //tag::mapping-filter-Account-example[] + @Entity(name = "Account") + @FilterDef( + name="activeAccount", + parameters = @ParamDef( + name="active", + type="boolean" + ) + ) + @Filter( + name="activeAccount", + condition="active_status = :active" + ) + public static class Account { - private Double rate; + @Id + private Long id; - private boolean active; + @ManyToOne(fetch = FetchType.LAZY) + private Client client; - //Getters and setters omitted for brevity + @Column(name = "account_type") + @Enumerated(EnumType.STRING) + private AccountType type; - //end::mapping-filter-example[] - public Long getId() { - return id; - } + private Double amount; - public void setId(Long id) { - this.id = id; - } + private Double rate; - public Client getClient() { - return client; - } + @Column(name = "active_status") + private boolean active; - public void setClient(Client client) { - this.client = client; - } + //Getters and setters omitted for brevity + //end::mapping-filter-Account-example[] + public Long getId() { + return id; + } - public AccountType getType() { - return type; - } + public Account setId(Long id) { + this.id = id; + return this; + } - public void setType(AccountType type) { - this.type = type; - } + public Client getClient() { + return client; + } - public Double getAmount() { - return amount; - } + public Account setClient(Client client) { + this.client = client; + return this; + } - public void setAmount(Double amount) { - this.amount = amount; - } + public AccountType getType() { + return type; + } - public Double getRate() { - return rate; - } + public Account setType(AccountType type) { + this.type = type; + return this; + } - public void setRate(Double rate) { - this.rate = rate; - } + public Double getAmount() { + return amount; + } - public boolean isActive() { - return active; - } + public Account setAmount(Double amount) { + this.amount = amount; + return this; + } - public void setActive(boolean active) { - this.active = active; - } + public Double getRate() { + return rate; + } - //tag::mapping-filter-example[] - } - //end::mapping-filter-example[] + public Account setRate(Double rate) { + this.rate = rate; + return this; + } + + public boolean isActive() { + return active; + } + + public Account setActive(boolean active) { + this.active = active; + return this; + } + + //tag::mapping-filter-Account-example[] + } + //end::mapping-filter-Account-example[] }