Considere el siguiente modelo JAVA para hibernar :
@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;
}
y el siguiente modelo para la serialización de API (utilizando el controlador de Spring Boot Rest):
public class PersonVO {
public Long id;
public String fullName;
}
Lo que quiero es:
- Aplicar un poco de filtrado a la Persona (estáticamente definido)
- Aplicar un poco de filtrado en PersonVO (obtener de @RequestParam)
En C # .NET podría hacer como:
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();
Lo que obtuve en Java es:
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?
}
Quiero haber separado la "proyección al modelo VO" de la "expresión de donde" se le aplicó, pero que se aplique indirectamente si se usa una columna proyectada (como fullName).
¿Es esto posible en Java? ¿Usando qué? Criterios? Querydsl? ¿Corriente? (no se quede necesariamente con la muestra de Java)
stream()
para consultar la base de datos. Creo que esto puede responder parcialmente a mi pregunta. Pero lo mantendré abierto para ver si alguien puede responder eso con un ejemplo concreto (preferiblemente usando hibernate como orm).
Stream
s, podría haber hecho algo como: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());
donde sePredicate
usa el utilizado en el pingfilter
posteriormap
PersonV0