Betrachten Sie das folgende JAVA-Modell für den Ruhezustand :
@Entity
@Table
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
@Column
public String firstName;
@Column
public String lastName;
@Column
public Boolean active;
}
und das folgende Modell für die API-Serialisierung (unter Verwendung des Spring Boot Rest Controllers):
public class PersonVO {
public Long id;
public String fullName;
}
Was ich will ist:
- Lassen Sie die Person filtern (statisch definiert)
- Lassen Sie einige Filter bei der PersonVO anwenden (erhalten Sie von @RequestParam)
In C # .NET könnte ich wie folgt machen:
IQueryable<Person> personsQuery = entityFrameworkDbContext.Persons;
// FIRST POINT - Here i could make some predefined filtering like 'only active', 'from the same city'... at the database model
personsQueryWithPreDefinedFilters = personsQuery.Where(person => person.active == true);
IQueryable<PersonVO> personsProjectedToVO = personsQueryWithPreDefinedFilters.Select(person => new PersonVO()
{
id = person.id,
fullName = person.firstName + " " + person.lastName
});
// SECOND POINT - At this point i could add more filtering based at PersonVO model
if (!String.IsNullOrWhiteSpace(fullNameRequestParameter)) {
personsProjectedToVO = personsProjectedToVO.Where(personVO => personVO.FullName == fullNameRequestParameter);
}
// The generated SQL at database is with both where (before and after projection)
List<PersonVO> personsToReturn = personsProjectedToVO.ToList();
Was ich in Java bekommen habe ist:
CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
CriteriaQuery<PersonVO> cq = cb.createQuery(PersonVO.class);
Root<Person> root = cq.from(Person.class);
// FIRST POINT - Here i could make some predefined filtering like 'only active', 'from the same city'... at the database model
cq.where(cb.equal(root.get(Person_.active), true));
Expression<String> fullName = cb.concat(root.get(Person_.firstName), root.get(Person_.lastName));
cq.select(cb.construct(
PersonVO.class,
root.get(Person_.id),
fullName
));
// SECOND POINT - At this point i could add more filtering based at PersonVO model??? HOW???
if (fullNameRequestParameter != null) {
cq.where(cb.equal(fullName, fullNameRequestParameter));
// i only could use based at the fullName expression used, but could i make a Predicate based only on PersonVO model without knowing or having the expression?
}
Ich möchte die "Projektion auf das VO-Modell" von dem darauf angewendeten "where-Ausdruck" getrennt haben, habe sie aber indirekt angewendet, wenn eine projizierte Spalte (wie fullName) verwendet wird.
Ist das in Java möglich? Mit was? Kriterien? Querydsl? Strom? (Halten Sie sich nicht unbedingt an die Java-Probe)
java
hibernate
java-stream
projection
querydsl
jvitor83
quelle
quelle
Stream
s hätten Sie so etwas wie -personList.stream().filter(p -> p.active).map(p -> new PersonV0(p.id, p.firstName + " " + p.lastName)).filter(pv -> pv.fullName.equals(fullNameRequestParameter)).collect(Collectors.toList());
wo derPredicate
imfilter
After-map
Ping verwendete basiertPersonV0
stream()
Abfragen der Datenbank ermöglichen kann. Ich denke, das kann meine Frage teilweise beantworten. Aber ich werde es offen halten, um zu sehen, ob jemand dies mit einem konkreten Beispiel beantworten kann (vorzugsweise mit Ruhezustand als Orm).Antworten:
Die JPA Criteria API verfügt nicht über solche Funktionen. Es ist auch nicht leicht zu lesen 😊
JPA Criteria API
In der Kriterien-API müssen Sie die wiederverwenden
Expression
.Der Arbeitscode sieht folgendermaßen aus:
Der generierte SQL-Code:
JPA Criteria API und
@org.hibernate.annotations.Formula
Der Ruhezustand hat eine Anmerkung
org.hibernate.annotations.Formula
, die den Code ein wenig vereinfachen kann.Fügen Sie der Entität ein berechnetes Feld hinzu, das mit Anmerkungen versehen ist
@Formula("first_name || ' ' || last_name")
folgenden :Verweisen Sie in der JPA Criteria API-Abfrage auf das Feld
fullName
:Und das generierte SQL:
Hibernate Criteria API
Die Hibernate Criteria API (seit Hibernate 5.2 zugunsten der JPA Criteria API veraltet) ermöglicht die Verwendung von Aliasen. Aber nicht alle Datenbanken erlauben die Verwendung von Aliasen (z
(full_name || ' ' || last_name) as full_name
) in awhere
Klausel zu verwenden.Laut den PostgreSQL-Dokumenten :
Es bedeutet die SQL-Abfrage
funktioniert nicht in PostgreSQL.
Die Verwendung eines Alias in einer
where
Klausel ist daher keine Option.quelle
Beachten Sie, dass Sie Ihre Spaltennamen in Schnittstellen gleich "getters" nennen müssen (getFirstName = firstName)
Es ruft eine schnittstellenbasierte Projektion auf. Dann können Sie eine Instanz erstellen von
PersonVO
:Benötigen Sie das?
quelle
Mit dieser http://www.jinq.org/ Bibliothek könnte ich es tun und auf den Ruhezustand (und folglich die Datenbank) angewendet werden.
Vielen Dank für die Hilfe!
quelle