Saludos,
Esta vez les comentare como he conseguido gestionar un control de usuario web que me permita hacer busquedas inteligentes, eficientes y eficaces.
Siempre que desarrollo intento que el codigo sea reutilizable al maximo, es asi que he implementado en mis sitios web busquedas al estilo de Google, usando siempre el mismo control para todos los casos de busqueda que necesite, es decir, un solo control llamado SmartSearch me resulve todos los problemas de busqueda que mis sitios puedan necesitar.
Por ejemplo:
En un formulario de facturacion o ventas, es necesario darle a nuestro usuario la opcion de buscar un proveedor o un cliente, asi como los productos que posee en su inventario y que necesitara elegir para facturarlos.
Siendo este el problema, deberiamos establecer codigo fuente de busqueda de tales entes en nuestra base de datos, asi como presentarlos en una lista y luego permitir que el usuario seleccione el dato deseado. Para esto, en programacion siemple deberiamos codificar cada caso. Si, tedioso y demorado, y es por eso que decidi implementar un control de usuario que al llenar unos pocos parametros me ayude a resolver estas tediosas busquedas en tiempos record.
Entrando a tema:
1) La idea es usar un solo textbox para que el usuario ingrese el texto buscado, ya sea codigo de cliente o nombre del cliente o numero de identificacion, en fin. He visto muchos sistemas que usan varios textbox o radiobutton para que el usuario deba elegir si quiere buscar por codigo o por nombre o por id, en fin, esto me parece en lo personal, algo muy desatendido, es decir, al construir un software debemos tener presente siempre que el tiempo y esfuerzo de muestros usuarios es muy valioso como para ponerlos a decidir cosas que nuestro sistema deberia resolver con un poco de ingenio, ademas, eso hara que nuestro sistema y por ende nuestro trabajo sea bien visto por nuestros usuarios, por lo tanto, nos recomendaran con sus amigos y conocidos, lo que implica en incremento en nuestros negocios. Desde luego no podemos por este hecho, desatender los recursos de los equipos, es decir, memoria, procesamiento y tiempos de respuesta, en fin, son muchos parametros que hay que tener presentes para hacer software de calidad, siempre funcionales y faciles de usar, que esto tambien es muy importante, ya que si nuestros sistemas son facilies de usar, no deberemos hacer manuales de usuario enormes que tambien es una perdidad de tiempo para nosotros programadores y el tiempo de adiestramiento del usuario sera muy corto tambien.
Otra cosa terrible que he visto por ahi es que, si el usuario digito un valor a buscar, si este no es exactamente identico a alguno de los datos almacenados en nuestra base de datos, el sistema no presenta resultados. Esto me parece de lo mas down… La idea de esta busqueda propuesta tambien es la de que el usuario por ejemplo esta buscando un cliente de nombre Fabricio Leon, pues el pueda escribir algo asi como esto: bricio on, o, fab leo, o, leo fab, o como se le ocurra y nuestro sistema debera interpretar la busqueda y mostrar las posibles alternativas.
2) Posterior a la orden de busqueda debemos presentar un listado con las coincidencias que hemos encontrado para que el usuario pueda elegir, para esto usaremos mediante javascript un webservice que nos retorne una htmltable con el listado, de tal manera, que no necesitaremos hacer un submit o postback de la pagina entera para que busque y traiga y presente los resultados.
Entonces necesitamos implementar un javascript que consuma un WebService y un control de usuario web que contenga estos elementos.
Comencemos por el principio,
1.- Creamos el WebService:
Dentro del WebService implementaremos una private function llamada SeekNow que realice la busqueda:
Los parametros de entrada para la function son:
TextToSearch: Aqui se recibirá el texto que el usuario ingreso en nuestro textbox y que desea buscar, recuerdan: “fab leo”
Q_Select: Aqui va el select que nos permitira ejecutar la busqueda dentro de nuestra base de datos, desde luego, este select es el que nos permitira el dinamismo de buscar en una u otra tabla, vista o conjunto de tablas, aqui depende la inventiva. Esta sentencia sql es la que nos dara dinamismo a nuestro control SmartSearch.
Q_Like: Nos permitira definir por que columnas comparar o buscar el TextToSearch
TBResults: Sera nuestra datatable que retornaremos llena de los resultados encontrados.
Q_TimeOutQueryOnSeconds: Este nos permite definir un timeout de respuesta de nuestra base de datos.
La idea de esta funcion es la de ir ensamblando una consulta sql, por ejemplo, en TextToSearch viene: “fab leo”, en Q_Select viene “select * from clientes”, y en Q_Like viene: “CodigoCliente,NombresCliente,IDCliente”. Entonces esta funcion lo que haria es ensamblar asi la consulta:
select * from clientes where (CodigoCliente like ‘%fab%’ and CodigoCliente like ‘%leo%’) or (NombresCliente like ‘%fab%’ and NombresCliente like ‘%leo%’) or (IDCliente like ‘%fab%’ and IDCliente like ‘%leo%’)
Por imaginarnos, las posibles respuestas serian: Fabricio Leon, Fabian Leonidas, Leonardo Fabio, en fin…
Ahora imaginen estamos buscando productos:
TextToSearch viene: “nit lano”, en Q_Select viene “select * from items”, y en Q_Like viene: “CodigoItem,DescripcionItem”. Entonces esta funcion lo que haria es ensamblar asi la consulta:
select * from items where (CodigoItem like ‘%nit%’ and CodigoItem like ‘%lano%’) or (DescripcionItem like ‘%nit%’ and DescripcionItem like ‘%lano%’)
Por imaginarnos, las posibles respuestas serian: Monitor Plano, Aeroplano Nitro, enfin…
Ahora veamos el codigo:
Private Function SeekNow(ByVal TextToSearch As String, ByVal Q_Select As String, ByVal Q_Like As String, Optional ByRef TBResults As Data.DataTable = Nothing, Optional ByVal Q_TimeOutQueryInSecconds As Integer = 30) As Data.DataTable
Dim result As String = ""
If Q_Like.IndexOf(":") >= 0 Then
Q_Like = Q_Like.Substring(Q_Like.IndexOf(":") + 1)
End If
If Q_Like.IndexOf(";") >= 0 Then
Q_Like = Q_Like.Substring(0, Q_Like.IndexOf(";"))
End If
If Q_Like.Trim.Length > 0 Then
If Q_Like.IndexOf(",") < 0 Then
Q_Like &= ","
End If
End If
'usaremos el espacio en blanco para identificar o separar las palabras dentro del TextToSearch. En la siguiente linea quitaremos los dobles o triples espacios que el usuario pudo haber escrito por error y reemplazaremos por comas, por eje: "fab leo" quedaria asi "fab,leo"" Dim B As String = TextToSearch.Trim.Replace(" ", ",").Replace(",,", ",").Replace(",,", ",")
Dim Campos As String = Q_Like 'Aqui la variable Campos guarda los campos o columnas de la tabla que compararemos, por ejemplo: "CodigoCliente,NombresCliente,IDCliente"
If B.Trim.Length > 0 Then
If B.IndexOf(",") < 0 Then 'Si no tenia espacios el TextToSearch entonces no tendra comas, asi que le adicionamos una por lo menos al final para poderla dividir sin que nos de error en el siguiente bucle
B &= ","
End If
For i As Integer = 0 To Campos.Split(",").Length - 1
If Campos.Split(",")(i).Trim.Length > 0 Then
If i > 0 Then ' Adicionamos un OR por cada palabra buscada y lo almacenamos en result siempre que no sea la primera pasada del bucle, por ejemplo quedaria algo asi: result ~ "CodigoCliente like '%fab%' or CodigoCliente like '%leo%'" Recuerda, en mysql % significa cualquier caracter(es) adelante o detrás
result &= " or "
End If
For j As Integer = 0 To B.Split(",").Length - 1
If B.Split(",")(j).Trim.Length > 0 Then
If j = 0 Then ' Si estamos iniciando el ensamblaje de la busqueda ponemos un parentesis al inicio
result &= " ("
End If
Try
result &= " " & Campos.Split(",")(i) & " like '%" & B.Split(",")(j) & "%' " 'Recuerdas?? result ~ "CodigoCliente like '%fab%' or CodigoCliente like '%leo%'"
If B.Split(",")(j + 1).Trim.Length Then
result &= " and "
End If
Catch ex As Exception
End Try
If j >= B.Split(",").Length - 1 Then
result &= ") "
End If
Else
result &= ") "
End If
Next
End If
Next
Q_Like = result
Else
'Exit Function
End If
' De encontrar una clausula Order By dentro del Q_Select, se reaoganiza la sentencia sql
Dim OrderBy As String = ""
If Q_Select.ToLower.IndexOf(" order by ") > 0 Then
OrderBy = Q_Select.Substring(Q_Select.ToLower.IndexOf(" order by "))
Q_Select = Q_Select.Substring(0, Q_Select.ToLower.IndexOf(" order by "))
End If
' Igual manera si se encuentra una clausula Group By
Dim GroupBy As String = ""
If Q_Select.ToLower.IndexOf(" group by ") > 0 Then
GroupBy = Q_Select.Substring(Q_Select.ToLower.IndexOf(" group by "))
Q_Select = Q_Select.Substring(0, Q_Select.ToLower.IndexOf(" group by "))
End If
' Igual con el Where, si ya existe se remmplaza la palabra Where con " Where y sus likes mas lo que ya tenia el Where de la sentencia sql" Y si no existia Where se lo adjunta
If Q_Select.ToLower.LastIndexOf(" where ") > 0 Then
If Q_Like.ToLower.IndexOf(" like ") >= 0 Then
Q_Select = Q_Select.Insert(Q_Select.ToLower.IndexOf(" where ") + 6, " (" & Q_Like & ") and ")
Else
Q_Select = Q_Select.Insert(Q_Select.ToLower.IndexOf(" where ") + 6, " ")
End If
Else
If Q_Like.Trim.Length > 0 Then
If Q_Like.IndexOf("%") >= 0 Then
Q_Select = Q_Select & " where " & Q_Like
End If
End If
End If
' A continuacion ensamblo la sentencia sql y uso una funcion DataRecovery que me ejecuta la consulta y me devuelve el resultado en una datatable
Return Lion.DataRecovery(Q_Select & GroupBy & OrderBy, TBResults, Q_TimeOutQueryInSecconds, , True, , False)
Catch ex As Exception
End Try
Return Nothing
End Function
La anterior es la función ’kernel’ o alma del proceso de búsqueda.
Como la funcion Seek nos devuelve una data table, la podriamos asignar a una GridView (GV1.datasource = seek(….)) y presentar sus resultados (GV1.databinding()) y listo, sin embargo, la idea propuesta es otra, y la desarrollamos a continuacion:
Vamos a implementar una nueva función que formatee nuestra tabla de resultados, dentro de una HtmlTable, y porque??, pues fácil, como la idea es llamar a este proceso de búsqueda desde una pagina web sin que esta incurra en un postback, entonces, podemos hacer un consumo de servicios via javascript, llamar a la función de búsqueda, y leer los resultados en forma de htmltable y publicar esta tabla en nuestra pagina. Esto hará transparente el proceso de busqueda en nuestro website.
Implementemos el retorno del htmltable:

tendras el codigo del retorno del htmltable?