Translate

miércoles, 11 de julio de 2012

Spring Data y QueryDSL operador like

QueryDSL like operator

Prerrequisitos: Conocimientos medios de QueryDsl.

El problema que resolvemos a continuación es el operador like usando QueryDSL. Si no quieres leerte todo el rollo te adelanto que el operador que buscas es containsIgnoreCase en vez de like pero tiene alguna pega que expongo a continuación.

Si has llegado hasta aquí buscando por google supongo que ya tendrás configurado tu entorno y QueryDsl para realizar tus consultas. Como ya sabemos la ventaja que te da QueryDsl es nos permite construir una query directamente sobre el código java de nuestro service.

Imaginemos que tenemos  el siguiente pojo

----
@Entity
@Document
public class Course implements Serializable {
 
 
 private static final long serialVersionUID = -7251789829032925885L;
 
 
 @Id
 private String id = UUID.randomUUID().toString();
 private String name; 
 private String description;
 private String companyOwner;
 private String metodology;

---

Una vez configurado QueryDsl automáticamente nos lo transforma nuestro pojo en el siguiente código.

----
/**
 * QCourse is a Querydsl query type for Course
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QCourse extends EntityPathBase<Course> {

    private static final long serialVersionUID = 430564814;

    public static final QCourse course = new QCourse("course");

    public final StringPath companyOwner = createString("companyOwner");

    public final StringPath description = createString("description");

    public final StringPath id = createString("id");

    public final StringPath metodology = createString("metodology");


    public QCourse(String variable) {
        super(Course.class, forVariable(variable));
    }

    public QCourse(Path<? extends Course> entity) {
        super(entity.getType(), entity.getMetadata());
    }

    public QCourse(PathMetadata<?> metadata) {
        super(Course.class, metadata);
    }


---

Esto nos permite hacer queries directamente con código java

----
BooleanBuilder builder = new BooleanBuilder();
   
   builder.and(QCourse.course.id.eq("id1"));
   builder.and(QCourse.course.name.like("Matematica"));

List<Course> data = (List<Course>) courseDao.findAll(builder.getValue()); 
      
   return data;

---


El problema es cuando queremos hacer una búsqueda sobre un campo String con lo que en SQL sería el operador LIKE, como por ejemplo Name like %Matematica% 

QueryDsl tiene el operador like pero su lo utilizamos nos da el siguiente error:
 
 
----
java.lang.UnsupportedOperationException: Illegal operation course.name like Matemáticas
 at com.mysema.query.mongodb.MongodbSerializer.visit(MongodbSerializer.java:225)
 at com.mysema.query.mongodb.MongodbSerializer.visit(MongodbSerializer.java:34)
 at com.mysema.query.types.expr.BooleanOperation.accept(BooleanOperation.java:52)
 at com.mysema.query.mongodb.MongodbSerializer.handle(MongodbSerializer.java:39)
 at com.mysema.query.mongodb.MongodbSerializer.visit(MongodbSerializer.java:98)
 at com.mysema.query.mongodb.MongodbSerializer.visit(MongodbSerializer.java:34)
 at com.mysema.query.types.OperationImpl.accept(OperationImpl.java:81)
 at com.mysema.query.mongodb.MongodbSerializer.handle(MongodbSerializer.java:39)
 at com.mysema.query.mongodb.MongodbQuery.createQuery(MongodbQuery.java:330)
 at com.mysema.query.mongodb.MongodbQuery.createCursor(MongodbQuery.java:240)
 at com.mysema.query.mongodb.MongodbQuery.createCursor(MongodbQuery.java:235)
 at com.mysema.query.mongodb.MongodbQuery.list(MongodbQuery.java:221)
 at org.springframework.data.mongodb.repository.support.QueryDslMongoRepository.findAll(QueryDslMongoRepository.java:113)


---
 
   
  La alternativa para que la operación sea la que deseamos es containsIgnoreCase


----

builder.and(QCourse.course.name.containsIgnoreCase("Matemati"));

---
 
  
  Esta búsqueda recuperará cualquier palabra en el nombre que contenga Matemati como por ejemplo, Matematica, Matematico, Matematicas ya esté en mayúsculas o minúsculas.


Lo que no encontrará este tipo de búsqueda son acentos, por ejemplo Matemáticas, así que no es una búsqueda full text pero se aproxima bastante.




miércoles, 4 de julio de 2012

Spring Data Mongodb Configurando WriteResultChecking Policy para lanzar excepciones

Setting WriteResultChecking Policy in order to throw Exceptions

Cuando trabajamos con Mongodb a la hora de hacer Queries debemos de comprobar el objeto WriteResult resultante para comprobar que la operación se ha realizado correctamente.


WriteResult wr = mongoOperations.updateFirst(
 new Query(where("id").is("objectId")),   
 new Update().push("favouriteUsers", idUser),Course.class);
  
 String error = wr.getError();




Para que no tengmos que hacer esto y si ocurre algún problema se lance una excepcion debemos de configurar Spring Data Mongo Db de la siguiente manera.

<mongo:mongo host="localhost" port="27017" id="mongo">
         <mongo:options connections-per-host="8"
                    threads-allowed-to-block-for-connection-multiplier="4"
                    connect-timeout="1000"
                    max-wait-time="1500"
                    auto-connect-retry="true"
                    socket-keep-alive="true"
                    socket-timeout="1500"
                    slave-ok="true"
                    write-number="1"
                    write-timeout="0"
                    write-fsync="true"/>
    </mongo:mongo>

 <mongo:repositories base-package="xx.xxxx.xxx"/>

 <mongo:db-factory dbname="database" mongo-ref="mongo" id="mongoDbFactory"/>
 
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    <property name="writeResultChecking" value="EXCEPTION"/>
<!-- propiedad usada para que si hay error devuelva una excepción y no haya que comprobarlo -->    
 </bean>


La clave está en la propiedad writeResultChecking que puede configurar con los valores NONE, LOG y EXCEPTION que es el caso que nos interesa.

Referencias:

Spring data mongo de documentacion

Ejemplo de configuración

miércoles, 27 de junio de 2012

Flex - itemCreationPolicy: La política de creación de un objeto es útil

Pre-requisitos: Conocimientos básicos de Flex.

Esta particularidad de Flex es bastante útil desde mi punto de vista por dos puntos principalmente.

  • Para ahorrar memoria.
  • Para mejorar el comportamiento al a vista del usuario.
Todo objecto que se añade en flex tiene una  itemCreationPolicy que puede ser de dos tipos

  • Deferred: Que hace que el objeto se cree cuando es instaciado. Valor por defecto
  • Inmediate: Que hace que el objeto se cree al inciar la aplicación.

El  comportamiento deferred es el que está puesto por defecto ya que si fuera al contrario y todos los componentes cargaran en nuestra aplicación esta podría consumir mucha memoria y perder rendimiento.

Los que tienen el valor deferred se crean cuando el objeto es instanciado es decir cuando aparece en pantalla y el objeto tes visible.

Pero en ciertos casos necesitamos que este objeto aunque no se vea en pantalla necesitamos que se cree para que por ejemplo se carguen en él unos datos recuperados de base de datos o que al cargase se ejecute algún evento que necesitemos que ocurra.

En estos casos lo mejor es poner el campo  itemCreationPolicy="immediate" para que aunque no sea visible se comporte como si lo fuera y se cree al cargase la pantalla.

Todos los componentes de flex tienen esta propiedad itemCreationPolicy y puede aplicase cuando se crea necesario:


 <s:Button id="newButtonImmediate" 
            includeIn="Immediate" 
            itemCreationPolicy="immediate"/>



Referencias:

http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf63611-7ffa.html