Normalmente los métodos de Spring Data retornan una o más instancias de la entidad raíz con la que tipamos el repositorio. Sin embargo, en algunas ocasiones necesitamos obtener proyecciones de estas entidades.

Supongamos que tenemos la siguiente entidad Usuario y queremos obtener una proyección con solo los atributos nombre, apellido y email.

@Entity
public class Usuario {
    @Id
    private Long id;
    private String nombre;
    private String apellido;
    private String emal;
    private String password;

    ...
}

Proyecciones basadas en interfaces

Proyecciones cerradas

public interface UsuarioPublico {
    String getNombre();
    String getApellido();
    String getEmail();
}

Lo único que tenemos que tener en cuenta para que esto funcione es que los nombres en los métodos coincidan con los nombres de los atributos de la entidad raíz del repositorio.

    List findByNombre(String nombre);

En este caso el interprete de consultas crea un proxy de la interfaz en tiempo de ejecución y ejecuta los métodos expuestos sobre la entidad Usuario.

Se consideran proyecciones cerradas a las que utilizan interfaces cuyos métodos coinciden con los de la entidad raíz. Utilizando este tipo de proyecciones Spring puede optimizar la ejecución de la consulta por que conoce todos los atributos para crear el proxy de la interfaz.

Proyecciones abiertas

Mediante este tipo de proyecciones se pueden calcular nuevos valores, para esto se puede utilizar la anotación @Value.

public interface NombreCompleto {
    @Value("#{target.nombre + ' ' + target.apellido}")
    String getNombreCompleto();
    …
}

La entidad raíz está disponible en la variable "target". Una interfaz de proyección que utiliza @Value es una proyección abierta. Spring Data no puede aplicar optimizaciones en la consulta, porque la expresión SpEL podría usar cualquier atributo de la entidad raíz.

Las expresiones utilizadas en @Value deben ser expresiones muy simples, una alternativa a esta anotación podría ser los métodos default (introducidos en Java 8), como se muestra en el siguiente ejemplo:

public interface NombreCompleto {

  String getNombre();
  String getApellido();

  default String getNombreCompleto() {
    return getNombre().concat(" ").concat(getApellido());
  }
}

Una segunda alternativa, más flexible, es implementar la lógica en un bean de Spring y luego invocarla desde la expresión SpEL.

@Component
public class UsuarioUtil {
    String getNombreCompleto(Usuario usuario) {
      return usuario.getNombre().concat(" ").concat(usuario.getApellido());
  }
}
public interface NombreCompleto {
    @Value("#{@usuarioUtil.getNombreCompleto(target)}")
    String getNombreCompletoBean();
    …
}
    List findByNombre(String nombre);

Conclusión

Las proyecciones nos permiten crear vistas personalizadas de nuestros modelos. Esto nos ayuda a reducir la cantidad de código y hace que el código sea más legible.

Proyecto de ejemplo

 

Mandanos tus sugerencias

Ayudanos con ideas para los artículos de este blog a contacto@somospnt.com

¡Seguínos en nuestras redes sociales para enterarte de los últimos posts!