Despues de un tiempo de descanso (del blog nada más!) obligado...en favor del Incentives Army...regreso para dar el penúltimo capítulo de la saga de "anécdotas" de Hibernate...saga que ha sido inspirada en el último proyecto terminado en JoeDayz, BSC.
Este episodio será dedicado a una de las mejores herramientas que tiene Hibernate: Criteria...en mi humilde opinión claro está u_u ...pero tambien espero poder hacerlo breve debido a que de este tema existen infinidad de información en la web.
Primero, qué es criteria? Bueno podriamos definirla como una especie de herramienta para realizar consultas a base de datos...una herramienta que difiere bastante de los modos anteriormente vistos (HQL y SQL).
Siguiendo con el mismo ejemplo de los anteriores posts usaremos la tabla DATA_DEMAND y su respectiva clase DataDemand.
En el primer post hablamos de como realizar querys dinámicos haciendo uso de HQL y como tendriamos orientarlos para evitar el engorro de las condicionales a usar. Para ello habiamos usado "1 = 1" para saltarnos no solo el hecho de usar el campo estado como primer filtro, sino tambien para armar fácilmente el query. Así:
[sourcecode language='java']
query.append(" from DataDemand ");
query.append(" where 1 = 1 "); <-------
if(coYear != null && coYear.length() > 0)
{
query.append(" and coYear = " + coYear);
}
if(coMonth != null && coMonth.intValue() > 0)
{
query.append(" and coMonth = " + coMonth);
}
if(coRegion != null && coRegion.intValue() > 0)
{
query.append(" and region.coRegion = " + coRegion);
}
if(coKpi != null && coKpi.length() > 0)
{
query.append(" and kpi.coKpi = '" + coKpi + "' ");
}
[/sourcecode]
Criteria no requiere ninguna especie de truco para hacer ello. Cómo? Así:
[sourcecode language='java']
DetachedCriteria criteria = DetachedCriteria.forClass(DataDemand.class);
if(coYear != null && coYear.length() > 0)
{
criteria.add(Restrictions.eq("coYear", coYear));
}
if(coMonth != null && coMonth.intValue() > 0)
{
criteria.add(Restrictions.eq("coMonth", coMonth));
}
if(coRegion != null && coRegion.intValue() > 0)
{
criteria.add(Restrictions.eq("region.coRegion", coRegion));
}
if(coKpi != null && coKpi.length() > 0)
{
criteria.add(Restrictions.eq("kpi.coKpi", coKpi));
}
criteria.add(Restrictions.eq("stDataDemand", "A"))
.addOrder(Order.desc("coYear"));
List list = getHibernateTemplate().findByCriteria(criteria);
[/sourcecode]
Lo primero que se observa es que se usa el objecto DetachedCriteria, en vez de usar session.createCriteria(DataDemand.class)...esto recuerden que se está desarrollando en una aplicacion con Spring =).
Luego de ello se observa el uso de Restrictions, esta clase nos permite usar operadores de igualdad y demás que se usan en los querys. Algunos de los filtros que le vamos agregando a nuestro query a través del método add de criteria podrian ser:
[sourcecode language='java']
Restrictions.eq(...,...)
Restrictions.in(..., coRegionList), donde coRegionList puede ser cualquier "derivado" de Collections...
Restrictions.between(...)
Restrictions.and(...,...)
Restrictions.isEmpty(...)
Restrictions.isNotEmpty(...)
Restrictions.isNotNull(...)
Etc...
[/sourcecode]
Para el caso del uso de funciones tales como MAX y MIN se debe hacer uso de ProjectionList, por ejemplo:
[sourcecode language='java']
ProjectionList projectionList = Projections.projectionList()
.add(Projections.max("coYear"));
[/sourcecode]
Y luego agregar el projectionList:
[sourcecode language='java'] criteria.setProjection(projectionList);
[/sourcecode]
A primera vista no se ve muy diferente, sin embargo podria decir que el código me parece más limpio, más directo y más elegante =P...hablando a nivel de querys orientados a objectos me refiero.
El nivel y la cantidad de métodos que nos ofrece esta librería es bastante grande. En las pruebas que he realizado ha sido la mejor cuando se trata de armar querys dinámicamente. Querys en los que se requiera mostrar la mayor parte de los atributos de los objecto obtenidos. Esto ya que siempre se requiere tener cuidado en el mapeo de los objectos como vimos en el Episodio II.
El siguiente post por fin espero cerrar esta saga con una breve comparativa entre los tipos de consultas a base de datos antes presentados.
Saludos, hasta la próxima.
viernes, 30 de enero de 2009
sábado, 10 de enero de 2009
Analizando querys…Episodio II: HQL y beans no mapeados
Bueno en este segundo post seguiremos en la linea de HQL directo...para no perder la línea (del tema claro xD) y despues seguir con otra formas (no hql puro) que nos brinde Hibernate para realizar la consultas a base de datos.
El segundo método que quiero analizar es cuando se hace uso de Beans no mapeados. Qué es esto?
Pues se trata de realizar el mapeo directo (sin métodos de asignación intermedia) de consultas hql hacia objetos de clases que no tienen su correspondiente mapping.
En el ejemplo del post anterior teniamos una tabla llamada DATA_DEMAND y su respectiva clase DataDemand (claro sin olvidarnos de su HBM respectivo). También la usaremos para este ejemplo y en los siguientes.
Asumiendo que DataDemand sea una clase que tiene varios atributos de objetos de otros tipos de clases tambien mapeadas, es decir muchas relaciones many-to-one en su HBM...
[sourcecode language='xml']
...
...
[/sourcecode]
Quizás al momento de cargar una lista, el query se ejecute rápidamente. Pero...si las relaciones many-to-one están mapeadas con
- Tenemos el fetch sin lazy, es decir, tal como se muestra en el ejemplo...aqui si solo accedemos a atributos property (como stDataDemand) no tendriamos problemas. Pero si accedemos a los mapeados como many-to-one (como región), entonces para cada objeto de la lista se realizará un select en tiempo de ejecución para acceder al objeto. Es decir, si la lista de objetos contiene 10 elementos, realizará 10 consultas a base de datos por cada región se acceda. Y si fueran 50? O 200? ^^ Lo mismo ocurre si usamos fetch="join".
- Ahhhhh pues ahora no...lo mapeamos con fetch="select" lazy="false" ^^. Jeje...seguimos analizando y vemos que ahora en vez de realizar el query al momento que accedemos al región ya no realizará el query...porque lo ejecuto al momento de realizar la consulta y trajo ya el objeto región lleno. Pero tenemos otro problema...todos los objetos vienen ya cargados y esto hace demasiado pesada a la lista...Y solo quiero la descripción de región T_T...Emmmm en el caso que hagamos fetch="join" lazy="false" seria lo mismo pero ejecutaria todo en una sola consulta...lógicamente xD.
Entonces...el problema radica en que no requiero todo un objeto (o más objetos) completo...solo requiero una descripción (o solo resultados puntuales)...en mi caso seria un uso incesario de espacio.
Qué hacer?
En mis tantas consultas a mis partners y a la web...halle una solución algo simpatica. Y ahora la comparto con ustedes.
Planteando que es lo que requiero exactamente: un objeto pequeño para mostrar tan solo una serie de descripciones en alguna página...no quiero que me traiga nada más que la descripcion del objeto y la de algunos de los objetos que tiene internamente.
Con HQL directo hariamos?
[sourcecode language='java'] ...
query.append(" select deDataDemand, region.deRegion, kpi.deKpi ");
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
...[/sourcecode]
De veras asi lo solucionamos? O_o! No lo creo...creo que seria...
[sourcecode language='java'] ...
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
...[/sourcecode]
Waaaaa...ahora levantamos todos? No, no es necesario toooooooodo . La solución bien podria ser la siguiente (al fin llegue al objetivo del post u_u)...
Definimos un bean con los atributos que requerimos y atención especial al constructor...puede tener otros contructores pero es importante tener uno al menos que inicialice todos los atributos que requerimos:
[sourcecode language='java'] public class BeanDataDemand {
private String deDataDemand;
private String deRegion;
private String deKpi;
public BeanDataDemand(String deDataDemand, String deRegion, String deKpi)
{
this.deDataDemand = deDataDemand;
this.deRegion = deRegion;
this.deKpi = deKpi;
}
...
}
[/sourcecode]
Ahora planteamos el query que mapeará directamente (sin requerir HBM) los resultados de nuestro query hacia nuestro BeanDataDemand:
[sourcecode language='java'] query.append("select new ").append(BeanDataDemand.class.getName());
query.append(" (deDataDemand, region.deRegion, kpi.deKpi) ");
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
List list = getHibernateTemplate().find(query.toString());
[/sourcecode]
Y ya! La lista list esta conformada por beans del tipo BeanDataDemand y puede ser usada como lo necesitemos. De esta manera podemos usar objetos más pequeños cuando la ocasión lo amerite.
Y bueno desviandome un poco del tema, HQL me refiero...tambien se podria hacer esto mismo con un query...
[sourcecode language='java'] sql.append(" SELECT DD.DE_DATA_DEMAND as \"deDataDemand\", ");
sql.append(" R.DE_REGION as \"deRegion\", ");
sql.append(" K.DE_KPI as \"deKpi\" ");
sql.append(" FROM ");
sql.append(" DATA_DEMAND DD, ");
sql.append(" REGION R, ");
sql.append(" KPI K ");
sql.append(" WHERE ");
sql.append(" DD.CO_REGION = R.CO_REGION ");
sql.append(" AND DD.CO_KPI = K.CO_KPI ");
sql.append(" AND DD.ST_DATA_DEMAND = 'A' ");
return findListOfBeans(sql.toString(), null, BeanDataDemand.class); [/sourcecode]
Todo depende de que se requiera hacer con el resultado que nos arrojará el query. En mi caso yo requeria hacer más ligera la lista de objetos que traia para solo mostrar un listado en una tabla para describir los objetos lo más posible.
En otros casos donde se podrian usar estos tipos de beans son donde se realizan operacion tal como SUM(DD.VALUE) y asi por el estilo...como decia en el párrafo anterior...todo depende de lo que se requiera.
En el siguiente post creo que ya veré el tema de criteria...ojalá sea pronto =D...saludos.
El segundo método que quiero analizar es cuando se hace uso de Beans no mapeados. Qué es esto?
Pues se trata de realizar el mapeo directo (sin métodos de asignación intermedia) de consultas hql hacia objetos de clases que no tienen su correspondiente mapping.
En el ejemplo del post anterior teniamos una tabla llamada DATA_DEMAND y su respectiva clase DataDemand (claro sin olvidarnos de su HBM respectivo). También la usaremos para este ejemplo y en los siguientes.
Asumiendo que DataDemand sea una clase que tiene varios atributos de objetos de otros tipos de clases tambien mapeadas, es decir muchas relaciones many-to-one en su HBM...
[sourcecode language='xml']
...
...
[/sourcecode]
Quizás al momento de cargar una lista, el query se ejecute rápidamente. Pero...si las relaciones many-to-one están mapeadas con
fetch="select" o fetch="join" pueden pasar dos cosas:- Tenemos el fetch sin lazy, es decir, tal como se muestra en el ejemplo...aqui si solo accedemos a atributos property (como stDataDemand) no tendriamos problemas. Pero si accedemos a los mapeados como many-to-one (como región), entonces para cada objeto de la lista se realizará un select en tiempo de ejecución para acceder al objeto. Es decir, si la lista de objetos contiene 10 elementos, realizará 10 consultas a base de datos por cada región se acceda. Y si fueran 50? O 200? ^^ Lo mismo ocurre si usamos fetch="join".
- Ahhhhh pues ahora no...lo mapeamos con fetch="select" lazy="false" ^^. Jeje...seguimos analizando y vemos que ahora en vez de realizar el query al momento que accedemos al región ya no realizará el query...porque lo ejecuto al momento de realizar la consulta y trajo ya el objeto región lleno. Pero tenemos otro problema...todos los objetos vienen ya cargados y esto hace demasiado pesada a la lista...Y solo quiero la descripción de región T_T...Emmmm en el caso que hagamos fetch="join" lazy="false" seria lo mismo pero ejecutaria todo en una sola consulta...lógicamente xD.
Entonces...el problema radica en que no requiero todo un objeto (o más objetos) completo...solo requiero una descripción (o solo resultados puntuales)...en mi caso seria un uso incesario de espacio.
Qué hacer?
En mis tantas consultas a mis partners y a la web...halle una solución algo simpatica. Y ahora la comparto con ustedes.
Planteando que es lo que requiero exactamente: un objeto pequeño para mostrar tan solo una serie de descripciones en alguna página...no quiero que me traiga nada más que la descripcion del objeto y la de algunos de los objetos que tiene internamente.
Con HQL directo hariamos?
[sourcecode language='java'] ...
query.append(" select deDataDemand, region.deRegion, kpi.deKpi ");
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
...[/sourcecode]
De veras asi lo solucionamos? O_o! No lo creo...creo que seria...
[sourcecode language='java'] ...
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
...[/sourcecode]
Waaaaa...ahora levantamos todos? No, no es necesario toooooooodo . La solución bien podria ser la siguiente (al fin llegue al objetivo del post u_u)...
Definimos un bean con los atributos que requerimos y atención especial al constructor...puede tener otros contructores pero es importante tener uno al menos que inicialice todos los atributos que requerimos:
[sourcecode language='java'] public class BeanDataDemand {
private String deDataDemand;
private String deRegion;
private String deKpi;
public BeanDataDemand(String deDataDemand, String deRegion, String deKpi)
{
this.deDataDemand = deDataDemand;
this.deRegion = deRegion;
this.deKpi = deKpi;
}
...
}
[/sourcecode]
Ahora planteamos el query que mapeará directamente (sin requerir HBM) los resultados de nuestro query hacia nuestro BeanDataDemand:
[sourcecode language='java'] query.append("select new ").append(BeanDataDemand.class.getName());
query.append(" (deDataDemand, region.deRegion, kpi.deKpi) ");
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
List list = getHibernateTemplate().find(query.toString());
[/sourcecode]
Y ya! La lista list esta conformada por beans del tipo BeanDataDemand y puede ser usada como lo necesitemos. De esta manera podemos usar objetos más pequeños cuando la ocasión lo amerite.
Y bueno desviandome un poco del tema, HQL me refiero...tambien se podria hacer esto mismo con un query...
[sourcecode language='java'] sql.append(" SELECT DD.DE_DATA_DEMAND as \"deDataDemand\", ");
sql.append(" R.DE_REGION as \"deRegion\", ");
sql.append(" K.DE_KPI as \"deKpi\" ");
sql.append(" FROM ");
sql.append(" DATA_DEMAND DD, ");
sql.append(" REGION R, ");
sql.append(" KPI K ");
sql.append(" WHERE ");
sql.append(" DD.CO_REGION = R.CO_REGION ");
sql.append(" AND DD.CO_KPI = K.CO_KPI ");
sql.append(" AND DD.ST_DATA_DEMAND = 'A' ");
return findListOfBeans(sql.toString(), null, BeanDataDemand.class); [/sourcecode]
Todo depende de que se requiera hacer con el resultado que nos arrojará el query. En mi caso yo requeria hacer más ligera la lista de objetos que traia para solo mostrar un listado en una tabla para describir los objetos lo más posible.
En otros casos donde se podrian usar estos tipos de beans son donde se realizan operacion tal como SUM(DD.VALUE) y asi por el estilo...como decia en el párrafo anterior...todo depende de lo que se requiera.
En el siguiente post creo que ya veré el tema de criteria...ojalá sea pronto =D...saludos.
lunes, 5 de enero de 2009
Analizando querys...Episodio I: HQL, el inicio de la saga
Bueno empezaré esto comentando algunas de las soluciones que he ido implementando con respecto a formas de consultar a la base de datos usando como framework de persistencia a Hibernate, compañero (para este ejemplo) de nuestro querido amigo Spring.
La mayoria de esta soluciones han sido planteadas sobretodo para mejorar la perfomance de los querys y...buscando que el usuario deje de susurrarnos al oido "más rápido"...en el buen sentido de la palabra claro está xD.
Para empezar haré algunas comparaciones entre algunos tipos de consultas que devuelvan los mismos resultados y analizaré la performance de cada uno de ellos.
Como bien dice el título primero iré a por el modo HQL, el más simple y el más directo que se puede hacer con Hibernate.
A ver...tenemos una tabla llamada DATA_DEMAND y su respectiva clase DataDemand (cualquier parecido con algun nombre de BSC...no es pura coincidencia =P)...y además un posible query dinámico (con filtros) sería:
[sourcecode language='java']
StringBuffer query = new StringBuffer();
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
if(coYear != null && coYear.length() > 0)
{
query.append(" and coYear = " + coYear);
}
if(coMonth != null && coMonth.intValue() > 0)
{
query.append(" and coMonth = " + coMonth);
}
if(coRegion != null && coRegion.intValue() > 0)
{
query.append(" and region.coRegion = " + coRegion);
}
if(coKpi != null && coKpi.length() > 0)
{
query.append(" and kpi.coKpi = '" + coKpi + "' ");
}
List list = getHibernateTemplate().find(query.toString());
return list;
[/sourcecode]
Como diria Jack el destripador...ahora vamos por partes ^^...
Como vemos la primera expresión condicional que usamos es "where stDataDemand = 'A'". La mayoria de nosotros usamos el campo estado de las tablas para iniciar los querys (sobretodo cuando tenemos que armarlos dinámicamente)...esto ya que es un campo que siempre estará, que casi siempre será un parámetro por el cual se deba realizar la búsqueda. Entonces asi tendriamos más facil armar del query para usar el prefijo AND en los demás parámetros a usar.
Ahora bien, yendo un poco más alla de esta facilidad para armar querys dinámicos que nos daría usar siempre el campo estado como primer filtro...nos podriamos preguntar cuantos registros de la tabla tendrán este valor? En el caso de la mayoria de aplicaciones que he desarrollado, este campo tiene a dos valores, entonces en el mejor de los casos la mitad de los registros tenian el valor indicado 'A' (aunque en realidad el 90% de los datos tenian el campo estado con valor ACTIVO).
Esto nos lleva a deducir que el query iniciaria levantando la mitad de los registros de la tabla al aplicar el primer filtro de búsqueda...y si la tabla tuviera tan solo ...por ejemplo...1000 registros? O_O! Este tipo de práctica podria llevarnos a iniciar la selección de información con demasiados registros...como 500 registros O_o!
Entonces que hacer? Bueno alguna vez en algun curso en la universidad aprendi la lección (yo tambien hacia esto XD, recordar que en Cato la mayoria de cursos de programación se desarrollan usando JDBC XD). Analizando un poco antes de realizar los querys y con ayuda de mi DBA (y apoyo del JP estrella XD) encontramos que un análisis pequeño antes de colocar el orden en que deberian ejecutarse los filtros de búsqueda nos ayudarian a mejorar la perfomance...aunque sea al inicio de manera imperceptible ^^.
Llegada a esta conclusión...como hariamos con el problema de donde se coloca el AND pues los querys dinámicos pueden empezar con cualquiera de los N filtros que se pasen...pues la solución fue la siguiente:
[sourcecode language='java']
StringBuffer query = new StringBuffer();
query.append(" from DataDemand ");
query.append(" where 1 = 1 ");
if(coYear != null && coYear.length() > 0)
{
query.append(" and coYear = " + coYear);
}
if(coMonth != null && coMonth.intValue() > 0)
{
query.append(" and coMonth = " + coMonth);
}
if(coRegion != null && coRegion.intValue() > 0)
{
query.append(" and region.coRegion = " + coRegion);
}
if(coKpi != null && coKpi.length() > 0)
{
query.append(" and kpi.coKpi = '" + coKpi + "' ");
}
query.append(" and stDataDemand = 'A' ");
List list = getHibernateTemplate().find(query.toString());
[/sourcecode]
Usando la condicional de "1 = 1" (la cual siempre devuelve verdadero) podriamos empezar a armar tranquilamente u,u nuestros querys, ordenando los filtros del modo más conveniente y sin preocuparnos de cual de los filtros es el primero para los siguientes anteponerlos con el AND.
Entonces el query ahora podria haber mejorado en algo su perfomance. Analizándolo muy superficialmente estariamos diciendo "dame los campos que tengan este año, con este mes, de esta región y con este KPI (un campo de la tabla no se asusten XD) y que además tengan estado A (activo)", en vez de "dame los campos tengan estado ACTIVO, con el año indicado, con este mes, de esta region y con este KPI".
Bueno este pequeño truquillo serviria cuando nuestras búsquedas no deberian levantar en primera instancia todos los registros ACTIVOS de una base de datos. Y si este fuera el caso entonces el query al ejecutarse sin filtros quedaria más o menos asi "from DataDemand where 1 = 1 and stKpipDataDemand = 'A' ", lo cual nos devolveria el resultado esperado.
En el episodio 2 analizaremos otra manera de ejecutar el mismo query...quizás usando criteria o beans no mapeados...quizás...quizás...quizás... XD
La mayoria de esta soluciones han sido planteadas sobretodo para mejorar la perfomance de los querys y...buscando que el usuario deje de susurrarnos al oido "más rápido"...en el buen sentido de la palabra claro está xD.
Para empezar haré algunas comparaciones entre algunos tipos de consultas que devuelvan los mismos resultados y analizaré la performance de cada uno de ellos.
Como bien dice el título primero iré a por el modo HQL, el más simple y el más directo que se puede hacer con Hibernate.
A ver...tenemos una tabla llamada DATA_DEMAND y su respectiva clase DataDemand (cualquier parecido con algun nombre de BSC...no es pura coincidencia =P)...y además un posible query dinámico (con filtros) sería:
[sourcecode language='java']
StringBuffer query = new StringBuffer();
query.append(" from DataDemand ");
query.append(" where stDataDemand = 'A'");
if(coYear != null && coYear.length() > 0)
{
query.append(" and coYear = " + coYear);
}
if(coMonth != null && coMonth.intValue() > 0)
{
query.append(" and coMonth = " + coMonth);
}
if(coRegion != null && coRegion.intValue() > 0)
{
query.append(" and region.coRegion = " + coRegion);
}
if(coKpi != null && coKpi.length() > 0)
{
query.append(" and kpi.coKpi = '" + coKpi + "' ");
}
List list = getHibernateTemplate().find(query.toString());
return list;
[/sourcecode]
Como diria Jack el destripador...ahora vamos por partes ^^...
Como vemos la primera expresión condicional que usamos es "where stDataDemand = 'A'". La mayoria de nosotros usamos el campo estado de las tablas para iniciar los querys (sobretodo cuando tenemos que armarlos dinámicamente)...esto ya que es un campo que siempre estará, que casi siempre será un parámetro por el cual se deba realizar la búsqueda. Entonces asi tendriamos más facil armar del query para usar el prefijo AND en los demás parámetros a usar.
Ahora bien, yendo un poco más alla de esta facilidad para armar querys dinámicos que nos daría usar siempre el campo estado como primer filtro...nos podriamos preguntar cuantos registros de la tabla tendrán este valor? En el caso de la mayoria de aplicaciones que he desarrollado, este campo tiene a dos valores, entonces en el mejor de los casos la mitad de los registros tenian el valor indicado 'A' (aunque en realidad el 90% de los datos tenian el campo estado con valor ACTIVO).
Esto nos lleva a deducir que el query iniciaria levantando la mitad de los registros de la tabla al aplicar el primer filtro de búsqueda...y si la tabla tuviera tan solo ...por ejemplo...1000 registros? O_O! Este tipo de práctica podria llevarnos a iniciar la selección de información con demasiados registros...como 500 registros O_o!
Entonces que hacer? Bueno alguna vez en algun curso en la universidad aprendi la lección (yo tambien hacia esto XD, recordar que en Cato la mayoria de cursos de programación se desarrollan usando JDBC XD). Analizando un poco antes de realizar los querys y con ayuda de mi DBA (y apoyo del JP estrella XD) encontramos que un análisis pequeño antes de colocar el orden en que deberian ejecutarse los filtros de búsqueda nos ayudarian a mejorar la perfomance...aunque sea al inicio de manera imperceptible ^^.
Llegada a esta conclusión...como hariamos con el problema de donde se coloca el AND pues los querys dinámicos pueden empezar con cualquiera de los N filtros que se pasen...pues la solución fue la siguiente:
[sourcecode language='java']
StringBuffer query = new StringBuffer();
query.append(" from DataDemand ");
query.append(" where 1 = 1 ");
if(coYear != null && coYear.length() > 0)
{
query.append(" and coYear = " + coYear);
}
if(coMonth != null && coMonth.intValue() > 0)
{
query.append(" and coMonth = " + coMonth);
}
if(coRegion != null && coRegion.intValue() > 0)
{
query.append(" and region.coRegion = " + coRegion);
}
if(coKpi != null && coKpi.length() > 0)
{
query.append(" and kpi.coKpi = '" + coKpi + "' ");
}
query.append(" and stDataDemand = 'A' ");
List list = getHibernateTemplate().find(query.toString());
[/sourcecode]
Usando la condicional de "1 = 1" (la cual siempre devuelve verdadero) podriamos empezar a armar tranquilamente u,u nuestros querys, ordenando los filtros del modo más conveniente y sin preocuparnos de cual de los filtros es el primero para los siguientes anteponerlos con el AND.
Entonces el query ahora podria haber mejorado en algo su perfomance. Analizándolo muy superficialmente estariamos diciendo "dame los campos que tengan este año, con este mes, de esta región y con este KPI (un campo de la tabla no se asusten XD) y que además tengan estado A (activo)", en vez de "dame los campos tengan estado ACTIVO, con el año indicado, con este mes, de esta region y con este KPI".
Bueno este pequeño truquillo serviria cuando nuestras búsquedas no deberian levantar en primera instancia todos los registros ACTIVOS de una base de datos. Y si este fuera el caso entonces el query al ejecutarse sin filtros quedaria más o menos asi "from DataDemand where 1 = 1 and stKpipDataDemand = 'A' ", lo cual nos devolveria el resultado esperado.
En el episodio 2 analizaremos otra manera de ejecutar el mismo query...quizás usando criteria o beans no mapeados...quizás...quizás...quizás... XD
Suscribirse a:
Comentarios (Atom)