Ignorar mayúsculas y tildes en ORACLE
¿A quién no le ha pasado esto?: Cuando la aplicación está casi terminada y la entrega está próxima, el tester se da cuenta de un pequeño (y básico) detalle que no habíamos tenido en cuenta: los formularios de búsqueda de nuestra aplicación deben ignorar mayúsculas y minúsculas y, por si fuera poco, también deben ignorar tildes.
La primera parte tiene una solución relativamente sencilla: ORACLE proporciona las funciones upper() y lower(), que devuelven una cadena de texto convertida a mayúsculas y a minúsculas respectivamente. Así, para crear un filtro en una sentencia SELECT que ignore mayúsculas y minúsculas (es decir, que sea CASE-INSENSITIVE), bastaría con lo siguiente (según queramos búsqueda exacta o aproximada):
select * from USUARIOS where upper(APELLIDOS) = upper('López')
select * from USUARIOS where upper(APELLIDOS) like '%' || upper('López') || '%'
Ahora nos queda la segunda parte: podemos ignorar las letras con tilde mediante la funcion translate(). Dicha funcion recibe tres parametros: una cadena de entrada sobre la que se quiere operar, un patrón con los caracteres que se quieren sustituir y otro patrón con los caracteres que sustituirán a los incluidos en el parámetro anterior. Así, la siguiente llamada a la función:
translate('Cadena 112234', '1234', 'abcd');
Devolverá el resultado ‘Cadena aabbcd’, al realizar la sustitución 1->a, 2->b, 3->c, 4->d. Si aplicamos la misma teoría a nuestras búsquedas, para no tener en cuenta ningún tipo de diéresis ni tilde, sustituiríamos las consultas anteriores por las siguientes:
select * from USUARIOS
where translate(upper(APELLIDOS), 'ÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛ', 'AEIOUAEIOUAEIOUAEIOU') = translate(upper('López'), 'ÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛ', 'AEIOUAEIOUAEIOUAEIOU')
select * from USUARIOS
where translate(upper(APELLIDOS), 'ÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛ', 'AEIOUAEIOUAEIOUAEIOU') like translate(upper('%López%'), 'ÁÉÍÓÚÄËÏÖÜÀÈÌÒÙÂÊÎÔÛ', 'AEIOUAEIOUAEIOUAEIOU')
Hecho esto, no tendremos que preocuparnos más ni de mayúsculas ni de tildes
Redimensionar un control de texto con el tamaño de su contenido
En ocasiones, trabajando con WinForms, nos encontramos con un control contenedor de un texto variable en el que, o nos sobra espacio o nos falta. La clase Graphics de System.Drawing nos proporciona un método tremendamente útil para saber el tamaño, en píxels, de una cadena de texto.
Veremos a continuación cómo redimensionar de forma dinámica un control dependiendo del tamaño del texto contenido. Para ello crearemos, por ejemplo, un TextBox al que llamaremos txtPrueba, y en el que albergaremos un texto, por ejemplo “Más vale pájaro en mano, que ciento volando”.
txtPrueba.Text = "Más vale pájaro en mano que ciento volando";
A continuación, declararemos dos variables enteras, una para el alto y otra para el ancho.
// Declaramos una variable entera para almacenar el nuevo ancho y el nuevo alto int nuevoAncho = 0; int nuevoAlto = 0;
Es ahora donde instanciaremos la clase Graphics a partir del control TextBox, y extraeremos la fuente que está utilizando.
// Creamos un objeto de tipo Graphics a partir del TextBox Graphics g = txt.CreateGraphics(); // Extraemos la fuente del TextBox Font fuente = txt.Font;
Obtenemos, a partir del objeto Graphics, su alto y ancho a partir del método MeasureString, que no hace otra cosa que medir, en pixels, el tamaño que ocupa la cadena con la fuente indicada.
nuevoAncho = (int)g.MeasureString(txt.Text, fuente).Width; nuevoAlto = (int)g.MeasureString(txt.Text, fuente).Height;
Por último, asignamos los nuevos valores de alto y ancho y refrescamos el control.
txt.Width = nuevoAncho; txt.Height = nuevoAlto; txt.Refresh();
A partir de estos conceptos básicos, se pueden encontrar multitud de utilidades a este proceso, como por ejemplo, redimensionar el desplegable de un ComboBox al tamaño del mayor de sus elementos.
Crear un campo autoincrementable en ORACLE
Para los que nos iniciamos en los Gestores de Bases de Datos con SQL Server, la transición a ORACLE resulta siempre más dura que cuando se realiza el camino inverso. Realizando una analogía simple, en mi caso podría decir que T-SQL es a PL/SQL lo que C# es a C++. Más complicación, más potencia… y un sistema más “tiquismiquis” que los desarrollados por Microsoft.
SQL Server proporciona una forma muy sencilla de crear campos autonuméricos, generalmente utilizados en los IDs de las claves primarias de las tablas. Para crear un campo autoincrementable, lo único que teníamos que hacer era editar las propiedades de la columna que queríamos convertir en autoincrementable, acceder a sus propiedades y seleccionar la opción [Especificación de Identidad] marcando la casilla (Identidad) e informando del número de inicio del índice (Inicialización de identidad) y el número de unidades que se incrementará cada vez que se intente insertar un registro (Incremento de identidad).
Oracle nos pone las cosas un poco más difíciles, obligándonos a realizar dos pasos para realizar el mismo procedimiento: crear una secuencia y crear un trigger.
Redimensión dinámica de imágenes
Siguiendo con la manipulación de imágenes en .NET, imaginemos que disponemos de una imagen de un tamaño considerable, bien en disco, bien en base de datos, y queremos enviarle al usuario un thumbnail de dicha imagen. ¡Ojo! No queremos mostrar la imagen completa con un estilo que modifique su alto y ancho, ya que con esto estaríamos enviando la imagen completa y luego modificaríamos su visualización en cliente, perdiendo el correspondiente (y valioso) ancho de banda.
En lugar de esto, sacrificaremos unos cuantos ciclos de CPU en pos de limitar el tráfico y realizaremos la operación de redimensionar la imagen en servidor para posteriormente enviarsela (más pequeñita o más grande) al cliente.
Para ello, nos crearemos una función llamada RedimensionarImagen que reciba tres parámetros: la imagen que queremos redimensionar, la nueva altura y la nueva anchura:
private System.Drawing.Bitmap RedimensionarImagen(System.Drawing.Image imagenOriginal, int alto, int ancho)
{
Lo primero que haremos será guardar el alto y el ancho de la imagen original.
int anchoOriginal = imagenOriginal.Width; int altoOriginal = imagenOriginal.Height;
A continuación declaramos dos variables de tipo float que almacenaran el porcentaje de escalado al que se va a ver sometida la imagen.
float porcentajeEscaladoX = (float)ancho / (float)anchoOriginal; float porcentajeEscaladoY = (float)alto / (float)altoOriginal;
El siguiente paso será definir una nueva altura para la imagen, multiplicando los valores originales por los factores que hemos obtenido en el paso anterior.
int nuevoAncho = (int)(anchoOriginal * porcentajeEscaladoX); int nuevoAlto = (int)(altoOriginal * porcentajeEscaladoY);
Ya tenemos las dimensiones de nuestra nueva imagen, ahora necesitaremos crear una instancia.
System.Drawing.Bitmap nuevaImagen = new System.Drawing.Bitmap(nuevoAncho, nuevoAlto);
Ahora instanciamos una superficie de dibujo de GDI+ a partir de la imagen para tratar el tamaño.
System.Drawing.Graphics superficieGDI = System.Drawing.Graphics.FromImage((System.Drawing.Image)nuevaImagen);
Indicamos el modo de interpolación (en nuestro caso, Bicúbico Alta Calidad) y dibujamos la imagen con los nuevos valores de ancho y alto.
superficieGDI.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; superficieGDI.DrawImage(imagenOriginal, 0, 0, nuevoAncho, nuevoAlto);
Finalmente, liberamos el objeto GDI+ y devolvemos la imagen.
superficieGDI.Dispose(); return nuevaImagen; }
Et voilà!, hecho esto, obtendremos una imagen con el alto y ancho deseados.
Utilizar la Base de Datos como repositorio de imágenes (II)
En un artículo anterior aprendimos a almacenar una imagen en nuestra base de datos SQL Server. Ahora vamos a obtener la imagen que almacenamos previamente utilizando como dirección de la imagen un formulario aspx al que le pasaremos el identificador de la imagen a través de la QueryString.
Comenzaremos creando un nuevo formulario, al que llamaremos showImage.aspx. En el formulario, crearemos un nuevo método al que llamaremos ObtenerImagen, que recibirá como parámetro un entero (el ID de la imagen) y devolverá una secuencia de bytes (un byte[]).
byte[] ObtenerImagen(int idImagen)
{
}
Lo primero que hará este método será declarar una cadena de conexión y una sentencia SELECT que devuelva la imagen cuyo ID le pasamos. Para ello, declararemos ambas cadenas de texto.
string selectCommandText = "SELECT Fichero FROM Imagen WHERE IdImagen = " + Convert.ToString(idImagen); string ConnectionString = @"Data Source=DANIGARCIA\SQLSERVER2005;Initial Catalog=TestDB;Persist Security Info=True;User ID=dani;Password=c0ntr4s3n14";
A continuación podemos hacer dos cosas: crear un SqlCommand y ejecutar la sentencia SELECT, o bien declarar un DataSet y un SqlDataAdapter y dejar que sea éste último objeto el que nos proporcione los datos. Optaremos por la segunda opción, que pese a ser menos óptima, resulta mucho más cómoda
// Declaramos un DataSet y un SqlDataAdapter DataSet ds = new DataSet(); SqlDataAdapter adapter = new SqlDataAdapter(selectCommandText, selectConnectionString); // Rellenamos el DataSet con la consulta y la cadena de conexión anteriores adapter.Fill(ds);
Llegados a este punto, ya deberíamos tener almacenada en el DataSet la imagen que estábamos buscando. Por lo tanto, lo único que deberemos hacer será serializarla y devolverla, realizando las comprobaciones pertinentes:
if ((ds != null) && (ds.Tables.Count > 0) && (ds.Tables[0].Rows.Count > 0))
{
if (!ds.Tables[0].Rows[0].IsNull("Fichero"))
{
return ((byte[])(ds.Tables[0].Rows[0]["Fichero"]));
}
}
return null;
Llegados a este punto, codificaremos el contenido del Page_Load de nuestro aspx, comprobando la QueryString y pasándole el parámetro a nuestra función ObtenerImagen, declarando, en primer lugar, un array de Bytes para almacenar el resultado:
protected void Page_Load(object sender, EventArgs e)
{
byte[] bImagen = null;
if (!string.IsNullOrEmpty(Convert.ToString(Request.QueryString["id"])))
{
bImagen = ObtenerImagen(Convert.ToInt32((Convert.ToString(Request.QueryString["id"]))));
}
Si el resultado obtenido no es nulo, modificamos la respuesta para que sea de tipo imagen, haciendo lo siguiente:
if(bImagen != null)
{
Response.Clear();
Response.Buffer = true;
Response.ContentType = "image/jpeg";
Response.BinaryWrite(bImagen);
Response.End();
}
}
Con lo cual, si invocamos la ruta a través del ID, obtendremos directamente una imagen:
Esto es una prueba <br /> <img src="../aspx/showImage.aspx?id=1" />
Utilizar la Base de Datos como repositorio de imágenes (I)
En cierto proyecto necesitaba mostrar una serie de imágenes que el usuario debía insertar desde su equipo local. En un principio pensé enviar al servidor las imágenes, guardar la ruta relativa en Base de Datos y, cuando fuese necesario acceder a las imágenes, utilizar dicha ruta para acceder a la imagen. Pero no era tan sencillo. Por desgracia, no teníamos permiso de escritura en el disco duro, por lo que tenía que juguetear con las imágenes sin que éstas existieran físicamente. ¿Cómo? Almacenando y recuperando las imágenes de base de datos.
Guardando una imagen en SQL Server
Para empezar, veremos cómo almacenar en base de datos una imagen. Crearemos, desde el SQL Server Management Studio, una nueva tabla que tendrá tres campos:
- Un Id único entero y autoincrementable (IdImagen)
- Un nombre para la imagen nvarchar(50) (NombreImagen)
- Una secuencia de bytes, variable de tipo image (Fichero).
Creada la tabla, crearemos una página que, a partir de la ruta de la imagen, la inserte en base de datos. Podemos utilizar un Input File o un control similar para indicarle la ruta, pero aquí indicaremos únicamente el código necesario para subir la imagen dada su ruta física. Lo que haremos a continuación será lo siguiente:
- Crear una conexión a Base de Datos a partir de una cadena de conexión
string ConnectionString = @"Data Source=DANIGARCIA\SQLSERVER2005;Initial Catalog=TestDB;Persist Security Info=True;User ID=dani;Password=c0ntr4s3n14";
- Crear una cadena de texto con la sentencia INSERT.
string CommandString = "INSERT INTO Imagen(NombreImagen, Fichero) VALUES (@NombreImagen, @Fichero)";
- A continuación necesitaremos convertir nuestra imagen en un objeto que podamos manejar, por ejemplo un array de bytes. Para ello, a partir de la ruta física de la imagen crearemos un objeto de tipo System.Drawing.Bitmap que guardaremos en un MemoryStream que, a su vez, convertiremos en un array de bytes (byte[]).
byte[] bImagen = null; System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(@"C:\TEMP\inicio.jpg"); if (bmp != null) { bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); bImagen = ms.ToArray(); ms.Close(); }
- Instanciar un objeto de tipo SqlCommand a partir de la conexión y de la sentencia INSERT.
SqlConnection conexion = new SqlConnection(ConnectionString); SqlCommand command = new SqlCommand(CommandString, conexion);
- Añadiremos ahora los SqlParameters necesarios al objeto SqlCommand con los datos a insertar en la base de datos. Estos serán, en nuestro caso, el nombre de la imagen y el array de bytes con la imagen.
SqlParameter nombre = new SqlParameter("@NombreImagen", "inicio.jpg"); SqlParameter imagen = new SqlParameter("@Fichero", bImagen);
- Por último, abrimos la conexión, ejecutamos la sentencia mediante ExecuteNonQuery() y cerramos la conexión. Hecho esto, tendremos nuestra imagen almacenada en base de datos.
conexion.Open(); command.Parameters.Add(nombre); command.Parameters.Add(imagen); command.ExecuteNonQuery(); conexion.Close();
Hecho esto insertaremos una imagen en una tabla de la base de datos.
Más adelante aprenderemos cómo recuperarla y referenciarla directamente a través de una URL con extensión aspx, es decir, invocar una ruta de tipo getImage.aspx?Id=xxx.
Recuperar una contraseña almacenada automáticamente mediante Javascript
Últimamente existe una cruenta batalla en la plataforma Windows entre Internet Explorer y Firefox. Personalmente, yo no me decanto hacia uno ni otro: utilizo Opera desde su versión 6.05, allá por 2002. Indico que utilizo Opera porque es un navegador que posee una funcionalidad llamada “varita mágica”, que no es más que un gestor de contraseñas en las que, pulsando ALT+ENTER se introducen automáticamente el nombre de usuario y la contraseña de una web en la que se hayan almacenado estos datos previamente.
Esta “comodidad” tiene un precio: a veces, de tanto utilizar este sistema, se me olvida alguna contraseña a causa del desuso, lo que causa que mi navegador la conozca y yo no.

Para paliar esta posibilidad, teniendo acceso a la página con el nombre de usuario y la contraseña, es posible averiguar el contenido del campo oculto entre asteriscos mediante una pequeña “treta” en Javascript. Lo primero que deberemos hacer será visualizar el código fuente de nuestra página (normalmente, haciendo click derecho sobre la misma y pulsando “Ver código fuente” o algo así, dependiendo del navegador).
Una vez visualizado, comprobamos la etiqueta que se muestra antes del campo que alberga la contraseña. En GMail, por ejemplo, “Contraseña”. Buscaremos este texto en el código fuente, obteniendo algo como lo que sigue: Como podemos observar, nos encontramos con un Input con un campo ID.

El valor de esa variable, en nuestro caso “Passwd”, es lo que nos interesa. Volveremos a nuestra página, y escribiremos lo siguiente en nuestra barra de navegación:
javascript:alert((document.getElementById('Passwd')).value);
Lo que le estamos diciendo a nuestro navegador es: “Ejecuta el siguiente código javascript: muestrame una alerta con el valor del elemento cuyo ID es ‘Passwd’”.
![]()
Acto seguido, se mostrará el contenido del campo en texto plano.

Es ahora tarea del usuario el ejecutar este código lejos de la vista de un posible mirón y, por supuesto, en un PC no comprometido…
Variables de servidor en ASP.NET
Nuestro servidor ASP.NET aloja una gran cantidad de información útil que, en determinado momento, puede salvarnos de situaciones complejas. Este conjunto de variables puede consultarse mediante el objeto Request.ServerVariables[<NombreVariable>]. Así, si realizamos la siguiente consulta:
string navegador = Request.ServerVariable["HTTP_USER_AGENT"];
La variable navegador alojará, como intuitivamente podremos imaginar, el navegador que está utilizando el cliente que se conecta a nuestro servidor, dato utilizado, por ejemplo, para estadísticas. En nuestro caso, el dato devuelto será el siguiente:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.0.3705; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Hay cantidad de variables de servidor cuya consulta puede hacernos la vida más fácil. Como ejemplo, indicaremos algunas de ellas:
| VARIABLE | SIGNIFICADO | EJEMPLO |
|---|---|---|
| SERVER_PROTOCOL | Protocolo de conexión | HTTP/1.1 |
| REMOTE_ADDR | Dirección IP Remota | 80.24.53.11 |
| LOCAL_ADDR | Direccion IP Local | 127.0.0.1 |
| PATH_INFO | Ruta de la aplicación | /MiAplicacion/Pagina.aspx |
| URL | URL de la página | /MiAplicacion/Pagina.aspx |
| AUTH_TYPE | Tipo de autenticación | Forms |
| SERVER_PORT | Puerto HTTP | 80 |
| HTTP_USER_AGENT | Navegador del usuario | Mozilla/4.0 (compatible; MSIE 8.0;… |
| HTTP_HOST | Nombre del host | MyMachine |
| SERVER_NAME | Nombre del servidor | MyMachine |
| SERVER_SOFTWARE | Servidor web | Microsoft-IIS/6.0 |
| APPL_PHYSICAL_PATH | Ruta física de la aplicación | C:\\Inetpub\\wwwroot\\MiAplicacion\\ |
| HTTPS | ¿Usa SSL? | off |
| AUTH_USER | Usuario autenticado | administrador |
| REMOTE_USER | Usuario remoto | administrador |
| HTTP_CONNECTION | Tipo de conexión HTTP | Keep alive |
| HTTP_ACCEPT_LANGUAGE | Idioma | es |
Existen más variables de servidor, y basta con recorrer con un bucle su contenido para echarle un vistazo a todas:
Hashtable hs = new Hashtable();
foreach (string s in Request.ServerVariables.AllKeys)
{
hs.Add(s, Request.ServerVariables[s]);
}
Enviar un e-mail desde .NET utilizando una cuenta SMTP de GMail
En mi proyecto de fin de carrera implementé un sistema automatizado de reservas que avisaba por e-mail del estado de las mismas. Para mi desgracia, olvidé mencionarlo durante la defensa, por lo que a nivel institucional fue una pérdida de tiempo, pero no así a nivel didáctico (que es, a fin de cuentas, lo importante).
Para implementarlo, utilicé los espacios de nombres System.Net y System.Net.Mail y una cuenta de Gmail a la que previamente le había activado el acceso POP/SMTP. Mandar un mail desde .NET es relativamente sencillo.
Si pensamos en la composición de un mail en términos de objetos, veremos que en realidad, enviar un mail es muy, pero que muy sencillo. Imaginemos que tenemos una cuenta en Gmail, por ejemplo ‘estoesunapruebademail25@gmail.com‘, cuya contraseña es ‘inteligible43‘. Queremos mandar un correo. ¿Qué información necesitamos?
- Un mensaje, que implementará la clase MailMessage.
- Un cliente de correo (SmtpClient) que se encargue de la autenticación y envío del mensaje.
A su vez, el mensaje necesitará:
- Uno o varios destinatarios.
- Un remitente.
- Un asunto (subject).
- El texto del mensaje.
Mientras que el cliente del correo necesitará saber:
- Servidor SMTP al que conectarse y puerto.
- Nombre de usuario y contraseña.
Almacenamiento y recuperación de parámetros en Sesión y ViewState
Muchas veces necesitamos utilizar parámetros entre distintos métodos de un mismo formulario web, o incluso entre formularios distintos. Una forma dinámica de realizar este intercambio de datos es la utilización del ViewState y del espacio de sesión.
Antes de embarcarnos a almacenar datos y datos en estos dos espacios de memoria, hay que dejar claras dos cosas:
- El ViewState se intercambia continuamente entre cliente y servidor, por lo que es aconsejable no sobrecargarlo. Al aumentar el ViewState, aumentará el tamaño de la página, y por consiguiente, el tráfico de datos y la velocidad de carga de la misma.
- La sesión se almacena en servidor, por lo que si nuestro sitio web posee una carga de datos moderada - alta, el rendimiento del mismo se verá penalizado. Nuevamente, es aconsejable utilizar con cautela este espacio de memoria.
Teniendo claros estos dos conceptos, utilizaremos el ViewState para almacenar datos locales (de una misma página) y la sesión para pasar parámetros entre distintas páginas sin hacer uso de la QueryString. Para los profanos en la materia, explicaremos que la QueryString es la colección de parámetros que pueden, opcionalmente, acompañar a la dirección de la página. Éstos parámetros ofrecen información directamente recopilable por nuestro formulario web, pero cuenta con la desventaja de que es visible para el usuario.

