HHH-11002 - Add documentation section about Filter and FilterDef
This commit is contained in:
parent
550ad824ac
commit
e52dab922c
|
@ -1238,7 +1238,7 @@ include::{extrasdir}/basic/mapping-where-persistence-example.sql[]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
When loading an `Account` entity, Hibernate is going to filter out all records that are not active.
|
When executing an `Account` entity query, Hibernate is going to filter out all records that are not active.
|
||||||
|
|
||||||
[[mapping-where-entity-query-example]]
|
[[mapping-where-entity-query-example]]
|
||||||
.Query entities mapped with `@Where`
|
.Query entities mapped with `@Where`
|
||||||
|
@ -1270,6 +1270,77 @@ include::{extrasdir}/basic/mapping-where-collection-query-example.sql[]
|
||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
|
[[mapping-column-filter]]
|
||||||
|
==== @Filter
|
||||||
|
|
||||||
|
The `@Filter` annotation is another way to filter out entities or collections using a custom SQL criteria, for both entities and collections.
|
||||||
|
Unlike the `@Where` annotation, `@Filter` allows you to parameterize the filter clause at runtime.
|
||||||
|
|
||||||
|
[[mapping-filter-example]]
|
||||||
|
.`@Filter` mapping usage
|
||||||
|
====
|
||||||
|
[source, JAVA, indent=0]
|
||||||
|
----
|
||||||
|
include::{sourcedir}/basic/FilterTest.java[tags=mapping-filter-example]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
If the database contains the following entities:
|
||||||
|
|
||||||
|
[[mapping-filter-persistence-example]]
|
||||||
|
.Persisting an 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.
|
||||||
|
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[]
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
Jut like with entities, collections can be filtered as well, but only if the filter is explicilty 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-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 teh `@Where` clause is that the filtering criteria can be customized at runtime.
|
||||||
|
====
|
||||||
|
|
||||||
[[mapping-column-any]]
|
[[mapping-column-any]]
|
||||||
==== @Any mapping
|
==== @Any mapping
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
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_
|
||||||
|
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
|
||||||
|
accounts0_.active = true
|
||||||
|
and a.client_id = 1
|
|
@ -0,0 +1,23 @@
|
||||||
|
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.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
|
|
@ -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)
|
|
@ -9,7 +9,7 @@ SELECT
|
||||||
c.account_type as account_5_0_1_
|
c.account_type as account_5_0_1_
|
||||||
FROM
|
FROM
|
||||||
Account c
|
Account c
|
||||||
WHERE ( c.active = 1 and c.account_type = 'CREDIT' ) AND c.client_id = 1
|
WHERE ( c.active = true and c.account_type = 'CREDIT' ) AND c.client_id = 1
|
||||||
|
|
||||||
SELECT
|
SELECT
|
||||||
d.client_id as client_i6_0_0_,
|
d.client_id as client_i6_0_0_,
|
||||||
|
@ -22,4 +22,4 @@ SELECT
|
||||||
d.account_type as account_5_0_1_
|
d.account_type as account_5_0_1_
|
||||||
FROM
|
FROM
|
||||||
Account d
|
Account d
|
||||||
WHERE ( d.active = 1 and d.account_type = 'DEBIT' ) AND d.client_id = 1
|
WHERE ( d.active = true and d.account_type = 'DEBIT' ) AND d.client_id = 1
|
|
@ -7,4 +7,4 @@ SELECT
|
||||||
a.account_type as account_5_0_
|
a.account_type as account_5_0_
|
||||||
FROM
|
FROM
|
||||||
Account a
|
Account a
|
||||||
WHERE ( a.active = 1 )
|
WHERE ( a.active = true )
|
||||||
|
|
|
@ -0,0 +1,252 @@
|
||||||
|
/*
|
||||||
|
* 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.basic;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.annotations.Filter;
|
||||||
|
import org.hibernate.annotations.FilterDef;
|
||||||
|
import org.hibernate.annotations.ParamDef;
|
||||||
|
import org.hibernate.annotations.Where;
|
||||||
|
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Vlad Mihalcea
|
||||||
|
*/
|
||||||
|
public class FilterTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
|
|
||||||
|
private static final Logger log = Logger.getLogger( FilterTest.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 -> {
|
||||||
|
|
||||||
|
Client client = new Client();
|
||||||
|
client.setId( 1L );
|
||||||
|
client.setName( "John Doe" );
|
||||||
|
entityManager.persist( client );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
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[]
|
||||||
|
|
||||||
|
|
||||||
|
//tag::mapping-filter-entity-query-example[]
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
List<Account> accounts = entityManager.createQuery(
|
||||||
|
"select a from Account a", Account.class)
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 3, accounts.size());
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
log.infof( "Activate filter [%s]", "activeAccount");
|
||||||
|
|
||||||
|
entityManager
|
||||||
|
.unwrap( Session.class )
|
||||||
|
.enableFilter( "activeAccount" )
|
||||||
|
.setParameter( "active", true);
|
||||||
|
|
||||||
|
List<Account> accounts = entityManager.createQuery(
|
||||||
|
"select a from Account a", Account.class)
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 2, accounts.size());
|
||||||
|
} );
|
||||||
|
//end::mapping-filter-entity-query-example[]
|
||||||
|
|
||||||
|
//tag::mapping-filter-collection-query-example[]
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
Client client = entityManager.find( Client.class, 1L );
|
||||||
|
assertEquals( 3, client.getAccounts().size() );
|
||||||
|
} );
|
||||||
|
|
||||||
|
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||||
|
log.infof( "Activate filter [%s]", "activeAccount");
|
||||||
|
|
||||||
|
entityManager
|
||||||
|
.unwrap( Session.class )
|
||||||
|
.enableFilter( "activeAccount" )
|
||||||
|
.setParameter( "active", true);
|
||||||
|
|
||||||
|
Client client = entityManager.find( Client.class, 1L );
|
||||||
|
assertEquals( 2, client.getAccounts().size() );
|
||||||
|
} );
|
||||||
|
//end::mapping-filter-collection-query-example[]
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::mapping-filter-example[]
|
||||||
|
public enum AccountType {
|
||||||
|
DEBIT,
|
||||||
|
CREDIT
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Client")
|
||||||
|
public static class Client {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "client")
|
||||||
|
@Filter(name="activeAccount", condition="active = :active")
|
||||||
|
private List<Account> accounts = new ArrayList<>( );
|
||||||
|
|
||||||
|
//Getters and setters omitted for brevity
|
||||||
|
|
||||||
|
//end::mapping-filter-example[]
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Account> getAccounts() {
|
||||||
|
return accounts;
|
||||||
|
}
|
||||||
|
//tag::mapping-filter-example[]
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Account")
|
||||||
|
@FilterDef(name="activeAccount", parameters=@ParamDef( name="active", type="boolean" ) )
|
||||||
|
@Filter(name="activeAccount", condition="active = :active")
|
||||||
|
public static class Account {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
private Client client;
|
||||||
|
|
||||||
|
@Column(name = "account_type")
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private AccountType type;
|
||||||
|
|
||||||
|
private Double amount;
|
||||||
|
|
||||||
|
private Double rate;
|
||||||
|
|
||||||
|
private boolean active;
|
||||||
|
|
||||||
|
//Getters and setters omitted for brevity
|
||||||
|
|
||||||
|
//end::mapping-filter-example[]
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClient(Client client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(AccountType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(Double amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Double getRate() {
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRate(Double rate) {
|
||||||
|
this.rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(boolean active) {
|
||||||
|
this.active = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tag::mapping-filter-example[]
|
||||||
|
}
|
||||||
|
//end::mapping-filter-example[]
|
||||||
|
}
|
Loading…
Reference in New Issue