Saya perlu membuat kueri kriteria dengan banyak gabungan kondisional dan klausa mana, dalam kasus seperti itu kode cenderung menjadi rumit dan dapat menghasilkan gabungan duplikat.
Misalnya saya memiliki struktur Tabel dan entitas JPA berikut:
ACCOUNT
ACCOUNT_ID
ACCOUNT_TYPE
PERSON
NAME
AGE
ACCOUNT_ID ( FK TO ACCOUNT )
ADDRESS_ID ( FK TO ADDRESS )
ADDRESS
ADDRESS_ID
LOCATION
COUNTRY
Jadi dengan asumsi saya menggunakan implementasi metamodel statis untuk menerapkan kueri kriteria.
Ini adalah contoh kode yang salah yang dapat menghasilkan gabungan duplikat:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Account> cq = cb.createQuery(Account.class);
cq.select(accountRoot).where(
cb.and(
cb.equal(accountRoot.join(Account_.person).get(Person_.name),"Roger"),
cb.greaterThan(accountRoot.join(Account_.person).get(Person_.age),18),
cb.equal(accountRoot.join(Account_.person)
.join(Person_.address).get(Address_.country),"United States")
)
)
TypedQuery<Account> query = entityManager.createQuery(cq);
List<Account> result = query.getResultList();
Kode di atas akan menghasilkan SQL dengan beberapa gabungan tabel yang sama:
Select
account0_.account_id as account1_2_,
account0_.account_type as account2_2_
from
account account0_
inner join
person person1_
on account0_.account_id=person1_.account_id
inner join
address address2_
on person1_.address_id=address2_.address_id
inner join
person person3_
on account0_.account_id=person3_.account_id
inner join
person person4_
on account0_.account_id=person4_.account_id
inner join
person person5_
on account0_.account_id=person5_.account_id
inner join
address address6_
on person5_.address_id=address6_.address_id
where
person3_.name=?
and person4_.age>18
and address6_.country=?
Solusi sederhana adalah dengan menjaga instance Gabungan untuk digunakan kembali dalam beberapa predikat seperti itu:
Root<Account> accountRoot = cq.from(Account.class);
Join<Account,Person> personJoin= accountRoot.join(Account_.person);
Join<Person,Address> personAddressJoin = accountRoot.join(Person_.address);
cq.select(accountRoot).where(
cb.and(
cb.equal(personJoin.get(Person_.name),"Roger"),
cb.greaterThan(personJoin.get(Person_.age),18),
cb.equal(personAddressJoin.get(Address_.country),"United States")
)
)
Oke, ini berhasil, Tetapi dengan kode yang sangat kompleks dengan beberapa tabel dan gabungan kondisional untuk kode tersebut cenderung menghasilkan kode Spaghetti! Percaya saya !
Apa cara yang lebih baik untuk menghindarinya?
join
. Apa yang Anda harapkan akan terjadi? Panggiljoin
sekali untuk setiap gabungan yang benar-benar Anda perlukan, dan gunakan kembali instanceJoin
yang dikembalikan. Anda sudah membuat duaJoin
instance yang Anda perlukan - gunakan saja! - person Rob   schedule 21.07.2015