Home » DB
Archiv der Kategorie: DB
Massen-Updates with JPA/Hibernate
update tableX set field1 = ‚value1‘ where field2 = ‚value2‘;
How is this implemented in JPA?
CriteriaBuilder builder = daoProvider.getEntityManager().getCriteriaBulder();
CriteriaUpdate<Entity> criteriaUpdate = builder.createCriteriaUpdate(Entity.class)
.set(root.get("field"), value)
.where(predicates);
int updated = entityManager.createQuery(criteriaUpdate).executeUpdate();
Logging von Hibernate SQL
Allgemeines Logging:
org.hibernate.SQL=DEBUG
Um die Parameter-Einfügungen in die Query zu loggen:
org.hibernate.type.descriptor.sql.BasicBinder=DEBUG
Spezifische Feld-Auswahl bei CriteriaAPI Mehrfach-Joins
Folgendes Beispiel zeigt, wie man spezifische Felder aus einem Join für die Resultat-Tabelle selektiert, indem man eine eingene Empfängerklasse (hier Container) definiert und in CriteriaQuery.multiselect(..) die felder selektiert, die man eben in der Resultattabelle haben will.
Gelehrt hat mich dies diese Stackoverflow-Seite.
/**
* Container, dem das spezifisch selektierten Feld übergeben wird
*/
public static class Container {
private String orderList;
private String businessCd;
/**
* CriteriaAPI übergibt an den Constructor.
*/
public Container(String orderList, String businessCd) {
this.orderList = orderList;
this.businessCd = businessCd;
}
public String getOrderList() {
return orderList;
}
public String getBusinessCd() {
return businessCd;
}
}
/**
* Class getting the data
*/
class GetTheData {
Set<String> getWithCriteriApiExercise(UniqueId businessExecutionId) {
CriteriaBuilder criteriaBuilder = daoProvider.getEntityManager().getCriteriaBuilder();
CriteriaQuery<Container> query = criteriaBuilder.createQuery(Container.class); // <-- !!! selbst definierte Empängerklasse (Container.class)
Root<HpsBusiness> root = query.from(HpsBusiness.class);
Join<HpsBusiness, HpsBusinessExec> joinBusiness = root.join(HpsBusiness._ATTR_businessExec, JoinType.INNER); //n:1
Join<HpsBusiness, HpsExcludedPos> joinExcludedPos = root.join(HpsBusiness._ATTR_excludedPosList, JoinType.INNER); //1:n
query.multiselect(joinExcludedPos.get(HpsExcludedPos._ATTR_orderIdList), root.get(HpsBusiness._ATTR_businessCd)) // <-- !!! multiselect Methode benutzen!!
.where(criteriaBuilder.and(criteriaBuilder.equal(joinBusiness.get(HpsBusinessExec._ATTR_id), businessExecutionId),
criteriaBuilder.equal(joinExcludedPos.get(HpsExcludedPos._ATTR_reason), "deprecated")));
TypedQuery<Container> typedQuery = daoProvider.getEntityManager().createQuery(query);
return typedQuery.getResultList().stream().map(c -> c.getOrderList() + "/" + c.getBusinessCd()).collect(Collectors.toSet()); // get the fields from Container
}
}
Mehrfach-Join in CriteriaAPI
Beachte, dass bei den Joins sowohl in richtung n:1 als auch in Richtung 1:n (mit _ATTR_excludedPosList) referenziert wird!
Set<String> getBusinessTypesWithExclusions(UniqueId businessExecutionId) { CriteriaBuilder criteriaBuilder = daoProvider.getEntityManager().getCriteriaBuilder(); CriteriaQuery<HpsBusiness> query = criteriaBuilder.createQuery(HpsBusiness.class); Root<HpsBusiness> root = query.from(HpsBusiness.class); Join<HpsBusiness, HpsBusinessExec> joinBusiness = root.join(HpsBusiness._ATTR_businessExec, JoinType.INNER); // <-- n : 1 Join<HpsBusiness, HpsExcludedPos> joinExcludedPos = root.join(HpsBusiness._ATTR_excludedPosList, JoinType.INNER); // <-- 1 : n query.select(root).where(criteriaBuilder.and(criteriaBuilder.equal(joinBusiness.get(HpsBusinessExec._ATTR_id), businessExecutionId), criteriaBuilder.equal(joinExcludedPos.get(HpsExcludedPos._ATTR_exclusionReasonType), ExclusionReasonType.EXCLUDED.name()))); return daoProvider.getHpsBusinessDao().find(query).stream().map(HpsBusiness::getBusinessCd).collect(Collectors.toSet()); }
Criteria API – Tutorials
Basics: https://www.baeldung.com/hibernate-criteria-queries
Overview: https://www.baeldung.com/learn-jpa-hibernate
Alternativ: https://www.objectdb.com/java/jpa/query/criteria
Speziell:
Oder man nimmt JPQL:
Criteria API: Join mit Filter auf beiden joined Tables
Der Knackpunkt is dieser:
Mit
Root<TabelleA> root = query.from(TabelleA.class)
wird die Ausgangstabelle (root) bezeichnet.
Mit
Join<TabelleA, TablleB> join = root.join(TabelleA.bRef);
wir TabelleB hinzu ge-joined.
Wichig Referenzen (z.B. der Filter auf das Feld feldXY) müssen nun von join aus gehen:
join.get(TablleB.feldXY)
Oder die ganze Where-Clause:
.where(criteriaBuilder.equal(root.get(TabelleA.id), "id000001"), criteriaBuilder.like( join.get(TablleB.feldXY), "%gesuchterInhalt%"))
Ganze Beispiel
CriteriaBuilder criteriaBuilder = ippDaoProvider.getEntityManager().getCriteriaBuilder(); CriteriaQuery<TabelleA> query = criteriaBuilder.createQuery(TabelleA.class); Root<TabelleA> root = query.from(TabelleA.class); Join<TabelleA, TablleB> join = root.join(TabelleA.bRef); query.select(root).where(criteriaBuilder.equal(root.get(TabelleA.id), "id000001"), criteriaBuilder.like( join.get(TablleB.feldXY), "%gesuchterInhalt%")); List<TabelleA> aList = daoProvider.getTableADao().find(query);
MS Access – Not in Query
In Oracle würde man schreiben:
select feldA from Table1 where feldA not in (select feldB from Table2);
Pendent in MS Access:
SELECT feldA FROM Table1 LEFT JOIN Table2 ON Table1.[feldA]=Table2.[feldB];
Criteria API: Select where in / In list where clause
CriteriaBuilder cb = daoProvider.getEntityManager().getCriteriaBuilder(); CriteriaQuery<Employee2> criteriaQuery = cb.createQuery(Employee2.class); Root<Employee2> employee2Root = criteriaQuery.from(Employee2.class); criteriaQuery.select(employee2Root).where(employee2Root.get(Employee2._ATTR_gpn).in(gpns)); TypedQuery<Employee2> query = daoProvider.getEntityManager().createQuery(criteriaQuery); List<Employee2> employees = query.getResultList();
JPA – Java Persistence API
Gute Einführungen: https://www.objectdb.com/java/jpa
JPA EntityManager and EntityManagerFactory Example
JPA: Named Query: https://examples.javacodegeeks.com/enterprise-java/jpa-named-query-example/
JDBC: https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.html
PL/SQL für Support-Scripts für DB-Änderungen
Problem:
Dem Produktions-Support eine sequenz von SQL Statements übergeben, bei der der Supporter über die SQL-Statements hinweg IDs propagieren muss?
Dabei verhindern, dass aufs Versehen zu viel gelöscht wird?
Lösung:
PL/SQL-Prozedur erstellen. Diese übernimmt das Propagieren der IDs. Die Gefahr des Vertippens ist vielfach kleiner, denn es muss nur die Prozedur kopiert werden. Diese kompiliert nicht, wenn beim kopieren etwas schief läuft.
Die PL/SQL-Prozedur kann einfach so in die SQLPlus-Konsole kopiert werden.
Links:
Weitere Links:
PLSQL Anfänger-Fallen/Tipps
‚/‘ zum Aktivieren am schluss der Stored Procedure, um diese zu aktivieren
Am schluss der Stored Procedure Definition mus ein auf einer neuern Zeile ein ‚/‘ angefügt werden, um diese im DB System auch zu aktivieren.
PLSQL Stored Procedures aufrufen:
execute meine_stored_procedure(‚parameterwert‘)
Parameterwert falls String in Hochkommas.
Input parameter von Stored Procedures sind immer ohne Längenangabe
varchar2(100) ist als Input-Parameter einer Stored Procedure falsch. Schreibe stattdessen: varchar ohne Längenangabe. Die Länge wird intern auf ein Maximum gesetzt.
Ouput ist nicht sichtbar!
Das problem ist dass der DBMS-Output nicht eingeschaltet ist. Mache das mit diesem Kommando:
SET
SERVEROUTPUT
ON
Compilierfehler werden nicht angezeigt
Symptom: Eine Stored Procedure wird kompiliert und einzig und allein diese Fehlermeldung erscheint: ORA-24344: success with compilation error
–> Die Kompilierfehler können angezeigt werden, indem SHOW ERRORS an die zu kompilierende Stored Procedure angefügt wird. Einfach nach dem „END;“ der stored Procedure anfügen, zusammen mit derselbigen markieren und abschicken.