Idee für ein stabiles Interface gesucht

dmike

Bekanntes Mitglied
Ich schreibe gerade für eine keine Webanwendung die Schnittstelle zur Datenbank bzw. zu den Repository-Klassen. Das ganze läuft über das Spring Data JPA

Die Webanwendung soll über die Repository-Klassen Objekte in der Datenbank suchen können. Also z.B.

userRepository.findByLastname(...)
carRepository.findByLicencePlateId()

Es ist aber schon klar, dass es nicht nur bei diesen beiden Abfragen bleiben wird. Deswegen würde ich gerne die Schnittstelle zwischen Webanwendung und den Repository-Klassen stabil halten.

Am liebste wärs mir wenn in der Webanwendung nur eine Art WHERE-clause formuliert wird, die dann durch die Repository Klasse ausgeführt wird. Dann brauch ich für alle zeiten nicht jedesmal eine neue Finder Methode zu definieren, wenn die Webanwendung eine neue Anforderung hat.

userRepository.find(...where...)


Plain-SQL als Where clause möchte ich aber nicht nehmen (injection Problem), also eine WHERE-clause in Form einer Criteria oder sowas wäre mir lieber . Hauptsache aber ist, dass in der Webanwendung keine direkte Datenbankanbindung über EntityManager, etc. existiert. Die Wenanwendung soll nur über die Repository kommunizieren.

Wie könnte man das machen?
 

dmike

Bekanntes Mitglied
Hi,

schon ein wenig älter: Welcome to Core J2EE Patterns! -> oder google nach dem DAO-Pattern!

Greetz

Die Repository Klassen von Spring Dasta JPA sind schon nach dem DAO Pattern entwicklet. Das löst aber das Problem nicht, dass ich jedesmal die DAO anfassen muss, wenn Clients neue Anforderungen haben. Dazu kommt das der Client die JPA Repository-Klassen nicht direkt sieht sondern nur eine Service-Schnittstelle. Die ich dann auch jedasmal neu anfassen müsstem, wenn für den Client eine neue Anfrage geschrieben werden soll.
 

Oliver Gierke

Mitglied
Ich empfehle einen Blick in die Referenzdokumentation zu Specifications [0]. Damit ist es möglich, Prädikate zu definieren die dann über eine stabile Methode findAll(Specification<T> spec) ausgeführt werden können. Dazu musst du nur das Repository interface JpaSpecificationExecutor erweitern lassen.

Die Definition der Specifications ist nicht gerade hübsch dank fehlender Closures und Umständlichkeit der JPA Criteria API. Als Alternative dazu kann man Querydsl [1] verwenden um Prädikate wirklich typsicher und kurz definieren zu können. Spring Data bietet auch dafür Unterstützung, das Repository erweitert dann einfach QueryDslPredicateExecutor.

Mehr Details dazu findest du in meinem Blogpost zu dem Thema [2].

Gruß
Ollie

[0] Spring Data JPA - Reference Documentation
[1] Querydsl
[2] Advanced Spring Data JPA – Specifications and Querydsl | SpringSource Team Blog
 

dmike

Bekanntes Mitglied
Ich empfehle einen Blick in die Referenzdokumentation zu Specifications [0]. Damit ist es möglich, Prädikate zu definieren die dann über eine stabile Methode findAll(Specification<T> spec) ausgeführt werden können. Dazu musst du nur das Repository interface JpaSpecificationExecutor erweitern lassen.

Die Definition der Specifications ist nicht gerade hübsch dank fehlender Closures und Umständlichkeit der JPA Criteria API. Als Alternative dazu kann man Querydsl [1] verwenden um Prädikate wirklich typsicher und kurz definieren zu können. Spring Data bietet auch dafür Unterstützung, das Repository erweitert dann einfach QueryDslPredicateExecutor.

Mehr Details dazu findest du in meinem Blogpost zu dem Thema [2].

Gruß
Ollie

[0] Spring Data JPA - Reference Documentation
[1] Querydsl
[2] Advanced Spring Data JPA – Specifications and Querydsl | SpringSource Team Blog

Super danke, genau so habe ich es dann auch gemacht. Mithilfe von QueryDSL bekomme ich das Interface stabil. Der einzige (kleine) Nachteil ist, dass die Clients Zugriff auf meine Qxxx-Klassen erhalten. Dafür sind die Queries aber wie du schon gesagt hast absolut typsicher.
 

Oliver Gierke

Mitglied
Einen Tod musst du sterben ;). Ich seh in vielen Projekten, dass die Prädikate nicht vollständig beliebig zusammengebaut werden sondern eher domänenspezifische, atomare Prädikate gebaut werden, die dann kombinierbar sind. Timo, der Lead von Querydsl, hat das hier [0] relativ schön zusammengestellt. Den Ansatz den ich meine findest du in der Klasse UserExpressions.

[0] Mysema Blog: Querydsl in the wild
 

dmike

Bekanntes Mitglied
Ich mach gleichmal hier weiter :)


Problem wie kann ich per QueryDSL ein embedded Object erreichen.

Folgende Fehlermeldung bekomme ich....
Java:
org.springframework.orm.hibernate3.HibernateSystemException: Could not determine a type for class: de.xxx.types.I18NString; nested exception is org.hibernate.HibernateException: Could not determine a type for class: de.xxx.types.I18NString


wenn ich das Folgende ausführe
Java:
        private static final QEvent $ = QEvent.event;
        I18NString title = new I18NString("English title",Locale.ENGLISH);
        BooleanExpression criteria = $.eventTitle.i18nStrings.contains(title);
        eventRepository.findAll(criteria);


Event enthält eine Property eventTitle vom Typ "LocalizedString"
Java:
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE} )
    private LocalizedString eventTitle = new LocalizedString();


LocalizedString wiederum hat eine Property i18nStrings welche aus einer Liste von Embedded Objects besteht.
Java:
	// [url=http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection]Java Persistence/ElementCollection - Wikibooks, open books for an open world[/url]
	@ElementCollection(fetch = FetchType.EAGER)
	@CollectionTable(name = "I18N_STRING", joinColumns = @JoinColumn(name = "ID"))
	@Column(name = "I18N_STRING")
	private Set<I18NString> i18nStrings = new HashSet<I18NString>();



Java:
@Embeddable
public class I18NString {
...
}


Soweit funktioniert alles (schreiben/lesen) nur die Formulierung von Predicates klappt noch nicht.
 

timowest

Mitglied
Das Problem mit I18NString ist, dass du keinen UserType dafuer definiert hast. Also entweder die Properties von I18NString einzeln matchen oder einen UserType (JDBC-Mapping) dafuer schreiben.

Hibernate kann die Identität von I18NString nicht definieren, da die Klasse keine Entity-Klasse ist und auch nicht direkt serialisierbar ist.
 

Ähnliche Java Themen


Oben