在 collections 上使用 @Filter 时,过滤的是 child entries (entities or embeddables) ,如果使用的是 join table 则需要使用 @org.hibernate.annotations.FilterJoinTable 指定 join table 的 column
@FilterJoinTable mapping usage
package org.example.demo.hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Persistence;
import org.hibernate.Session;
import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.FilterJoinTable;
import org.hibernate.annotations.ParamDef;
public class Test {
public static void main(String[] args) throws Exception {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Client client = new Client();
Account account1 = new Account();
account1.active = true;
client.accounts.add(account1);
Account account2 = new Account();
account2.active = false;
client.accounts.add(account2);
Account account3 = new Account();
account3.active = true;
client.accounts.add(account3);
em.getTransaction().begin();
em.persist(client);
em.persist(account1);
em.persist(account2);
em.persist(account3);
em.getTransaction().commit();
em.clear();
Client c = em.find(Client.class, client.id);
// [org.example.demo.hibernate.Test$Account@75699e35, org.example.demo.hibernate.Test$Account@7daa61f3, org.example.demo.hibernate.Test$Account@62315f22]
System.out.println(c.accounts);
em.clear();
em.unwrap(Session.class).enableFilter("firstAccounts").setParameter("maxOrderId", 1);
c = em.find(Client.class, client.id);
// [org.example.demo.hibernate.Test$Account@39ce27f2, org.example.demo.hibernate.Test$Account@5f2afe62]
System.out.println(c.accounts);
em.close();
factory.close();
}
@Entity(name = "Client")
@FilterDef(name = "firstAccounts", parameters = @ParamDef(name = "maxOrderId", type = "int"))
@Filter(name = "firstAccounts", condition = "order_id <= :maxOrderId")
public static class Client {
@Id
@GeneratedValue
private Long id;
@OneToMany
@OrderColumn(name = "order_id")
@FilterJoinTable(name = "firstAccounts", condition = "order_id <= :maxOrderId")
private List<Account> accounts = new ArrayList<>();
}
@Entity(name = "Account")
public static class Account {
@Id
@GeneratedValue
private Long id;
boolean active;
}
}
生成 SQL
alter table Client_Account drop constraint FKgjbkbp162w0o3ifqt8dinovhd
alter table Client_Account drop constraint FKatwtbdionrco2l5gtuxdjxmbw
drop table if exists Account cascade
drop table if exists Client cascade
drop table if exists Client_Account cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Account (id int8 not null, active boolean not null, primary key (id))
create table Client (id int8 not null, primary key (id))
create table Client_Account (Client_id int8 not null, accounts_id int8 not null, order_id int4 not null, primary key (Client_id, order_id))
alter table Client_Account add constraint UK_38qrg00qt74c1jwlf4wmhxopb unique (accounts_id)
alter table Client_Account add constraint FKgjbkbp162w0o3ifqt8dinovhd foreign key (accounts_id) references Account
alter table Client_Account add constraint FKatwtbdionrco2l5gtuxdjxmbw foreign key (Client_id) references Client
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
select nextval ('hibernate_sequence')
insert into Client (id) values (1)
insert into Account (active, id) values (true, 2)
insert into Account (active, id) values (false, 3)
insert into Account (active, id) values (true, 4)
insert into Client_Account (Client_id, order_id, accounts_id) values (1, 0, 2)
insert into Client_Account (Client_id, order_id, accounts_id) values (1, 1, 3)
insert into Client_Account (Client_id, order_id, accounts_id) values (1, 2, 4)
select test_clien0_.id as id1_1_0_ from Client test_clien0_ where test_clien0_.id=1
select accounts0_.Client_id as Client_i1_2_0_, accounts0_.accounts_id as accounts2_2_0_, accounts0_.order_id as order_id3_0_, test_accou1_.id as id1_0_1_, test_accou1_.active as active2_0_1_ from Client_Account accounts0_ inner join Account test_accou1_ on accounts0_.accounts_id=test_accou1_.id where accounts0_.Client_id=1
select test_clien0_.id as id1_1_0_ from Client test_clien0_ where test_clien0_.id=1
select accounts0_.Client_id as Client_i1_2_0_, accounts0_.accounts_id as accounts2_2_0_, accounts0_.order_id as order_id3_0_, test_accou1_.id as id1_0_1_, test_accou1_.active as active2_0_1_ from Client_Account accounts0_ inner join Account test_accou1_ on accounts0_.accounts_id=test_accou1_.id where accounts0_.order_id <= 1 and accounts0_.Client_id=1
@OrderColumn 从 0 起数。
注意,如果在 @OneToMany 上使用 @OrderColumn 则只能是单向关联。否则因为 @OneToMany 端必定是 inverse 端所以 order column 值总是 null 。