domingo, 30 de mayo de 2010

Trabajando LINQ para XML con Monodevelop Parte II de II

Esta es la segunda parte del post anterior Trabajando LINQ para XML con Monodevelop, aunque este tutorial supone que los dos proyectos están dentro la misma solución, los dos proyectos son independientes uno del otro, por lo que pueden crearse en diferentes soluciones.


Consultando XML con LINQ

Ahora agregamos un segundo proyecto a nuestra solución, este proyecto será una aplicación GTK# que llamaremos “SegundoLinqXML” como se muestra en la siguiente imagen y que nos mostrará como consultar el archivo XML con LINQ creado con la aplicación de consola anterior.



Utilizando el diseñador agregamos y acomodamos los siguientes controles GTK# con sus respectivos identificadores al formulario.
Tipo de control:Gtk.Entry NombretxtQuery

Tipo de control:Gtk.Button NombreBtnBuscar

Tipo de control:Gtk.RadioButton NombresRbCodigo,rbIdArticulo,rbNombre

Tipo de control:Gtk.TreeView NombresResultados

Colocando los controles el formulario deberá verse como en la siguiente imagen

El código completo es el siguiente:


El siguiente fragmento de código muestra como realizar la consulta del archivo XML donde la variable col adquiere el valor de cualquier elemento dentro del elemento table y donde el valor contenga el texto escrito dentro de txtQuery, es aquí donde en esencia se utilizan las expresiones de consulta de LINQ una vez que se carga el documento XML en memoria.




Construimos la aplicación pulsando el botón F8, seleccionamos el archivo de proyecto y haciendo click con e botón secundario del ratón seleccionamos la aplicación para que se inicie al ejecutar la solución, al ejecutarla teclear un valor y pulsar el botón consultar observaremos cualquiera de los siguientes resultados dependiendo del control radio seleccionado.




 Descarga el código fuente

miércoles, 26 de mayo de 2010

Trabajando LINQ para XML con Monodevelop Parte I de II

XML se ha convertido en un excelente estándar abierto para el intercambio de información entre aplicaciones de software debido a la manera de representar información estructurada, independiente de la plataforma, lenguaje de programación o sistema operativo, es utilizado extensamente en archivos y protocolos de Internet por ser un formato fácil de leer y suficientemente flexible para adaptarse a muchos propósitos. Debido a estas características XML y sus tecnologías están completamente integradas y soportadas por la plataforma .NET mediante un conjunto de clases que proporcionan lectura y escritura de documentos, validación, navegación, serialización, transformación y búsquedas. Aunque estas clases son suficientes para trabajar con XML su utilización no es sencilla y puede producir código difícil de mantener, por lo que .NET incorpora LINQ para XML (LINQ to XML) como una mejor manera de trabajar con XML.


Creando el archivo XML

Para mostrar de una manera práctica la utilización de LINQ para XML, ejecutamos MonoDevelop y creamos una nueva solución en el menú “Archivo”, del lado derecho de la ventana de nueva solución seleccionamos el icono que dice “Solución en blanco” y en el cuadro de texto nombre escogemos “LinqXML”, esta será la solución que contenga los dos proyectos de este tutorial.



Agregamos a nuestra solución un proyecto de consola, le llamamos CrearXML , como se muestra en la siguiente imagen.


Para que el soporte de LINQ a XML es importante hacer referencia a los siguientes ensamblados:

System.Linq Es el ensamblado principal y básico que contiene todas las clases e interfaces para trabajar con LINQ.

System.Xml.LinqContiene las clases y extensiones para manipular XML con LINQ.

Esto se logra haciendo click derecho sobre el archivo de proyecto y en el menú desplegable escogemos la opción “Editar referencias” (Edit References) como se muestra en la imagen siguiente.



Ahora completamos el código generado por monodevelop, para que el programa completo quede como en el siguiente listado.




La diferencia de la sintaxis para crear documentos XML con respecto a la sintaxis empleada con las clases del ensamblado System.Xml, es que esta sintaxis se enfoca más en los elementos (representados por la clase XElement) que en el documento (representado en la clase Xdocument ).
En este listado creamos el documento XML de una manera declarativa anidando varias objetos XElement dentro de un objeto Xdocument , al final llamamos al método Save para guardar el XML en el disco.
Construimos la aplicación pulsando la tecla F8 y al ejecutarse veremos el resultado en la ventana de salida de MonoDevelop como se muestra en la imagen siguiente.


 Descarga el código fuente

miércoles, 19 de mayo de 2010

El patrón singleton con Monodevelop y PostgreSQL


En el post anterior mostré un ejemplo utilizando el patrón Singleton con conexiones a bases de datos SQL Server ejecutándonse bajo Microsoft Windows, ahora mostraré las modificaciones que tuve que realizar a ese ejemplo para que funcione con
PostgreSQL como base de datos y Linux como sistema operativo.
Primeramente abrí el proyecto en Monodevelop, después descargue la última versión de la biblioteca Npgsql para tener actualizado los últimos cambios de esta biblioteca, lo cuál es recomendable ya que además de arreglar los errores el equipo responsable agrega nuevas funcionalidades, una vez descargada la biblioteca comence con las siguientes modificaciones:


1-.Quitar la referencia al ensamblado de Sql Server (System.Data.SqlClient) y reemplazarlo por el de PostgreSQL (Npgsql), esto se hace dentro del explorador de la solución, haciendo click derecho sobre las referencias como se muestra en la imagen.




Nos aparecerá la ventana "edit references", ahí escogemos la pestaña que dice "Ensamblado .Net" para buscar en el sistema de archivos en la ruta donde descargamos y descomprimimos la biblioteca Npgsql,esto para seleccionar el ensamblado Npgsql.dll como se muestra en la siguiente imagen.



2-. Reemplazar en el código de las clases DataBase y DataBase2 respectivamente el namespace System.Data.SqlClient por Npgsql
using System.Data.SqlClient;
por
using Npgsql;


3-. También en el código de esas clases reemplazar las líneas donde se hace la declaración del objeto que representa la conexión y donde se realiza la creación de dicho objeto, reemplazar las siguientes líneas:

SqlConnection _conn = null;
_conn = new SqlConnection();

por
NpgsqlConnection _conn = null;
_conn = new NpgsqlConnection();



4-. En estas mismas clases cambiar el tipo de excepción en el catch del try del metódo GetConnection().
catch(SqlException x)
por
catch(NpgsqlException x)



5-. Reemplazar el evento StateChange del objeto NpgsqlConnection y el delegado asociado al evento, por una propiedad de tipo string
que infome de las características de la conexión, esto debido a que aún el proveedor de datos de postgreSQL no cuenta con esta característica.

StateChange += delegate(object o,StateChangeEventArgs args){
Info = String.Format(" {1}| {2}| {3}|",args.CurrentState.ToString(),
System.DateTime.Now.ToLocalTime(), _conn.DataSource,_conn.Database);

por
Info = String.Format(" {0}|{1}| {2}| {3}|",GetCurrentState,System.DateTime.Now.ToLocalTime(),
_conn.DataSource ,_conn.Database);

Agregando la siguiente propiedad
public string GetCurrentState{ get {return (IsOpen == true ? "Open" : "Closed");}}



Terminando los cambios debemos de configurar MonoDevelop para que al ejecutar la aplicación el programa se ejecute en una terminal propia y no en la ventana de salida (output) de MonoDevelop, esto se hace en el menú principal en la opción "Proyecto" eligiendo el submenú "Opciones", nos mostrará una pantalla como la siguiente imagen.



Después de estos cambios podemos observar el resultado, de forma idéntica al resultado logrado en la plataforma Microsoft.
Ingreso de los parámetros de conexión

Sin el uso del patrón Singleton, cambian los tiempos en la conexión

Usando el patrón Singleton, el tiempo es único.


 Descarga el código fuente

lunes, 3 de mayo de 2010

El patrón singleton


Muchos problemas de rendimiento (performance) y de escalabilidad (scalability) ocurren si no manejamos correctamente las conexiones a las bases de datos, hay que tener en presente que las conexiones para acceder a una base de datos son un recurso que consume memoria y tiempo de procesador, por lo que solo se deben crear las conexiones necesarias para el funcionamiento de las aplicaciones y estas deben cerrarse tan pronto hayan sido ocupadas.
Una buena práctica es que todas las clases que acceden a los recursos de la base de datos utilicen siempre una única conexión sin importar el número de instancias que estas clases generen al ser ejecutadas dentro de una aplicación, una solución recomendada a este escenario es utilizar los patrones de diseño de software.


Conectarse a una base de datos con el patrón Singleton


Es un patrón de diseño del tipo creacional que nos asegura la creación de únicamente la instancia de un objeto sin importar el número de veces que se intenten crear más instancias de ese objeto.
citando el clásico libro de the gang of four Design Patterns:Elements of Reusable Object-Oriented Software, 1995, Pearson Addison Wesley "The Singleton design pattern must ensure a class only has one instance, and provide a global point of access to it"

Este patrón se utiliza para representar un objeto de hardware (por ejemplo una impresora), un componente del sistema operativo (un archivo o un directorio) o bien un recurso externo limitado (como una conexión a una base de datos), esta instancia revisará si ya ha sido creada, atenderá las peticiones de los objetos que la utilicen como un punto global de acceso (similar a una variable global) y sera responsable del mantener el seguimiento de su estado.
El esqueleto clásico de un Singleton es el siguiente:

A continuación voy a mostrar el ejemplo de una clase que representa una conexión a una base de datos sin utilizar el patrón Singleton, para mostrar como se crea una conexión por cada ocasión que nosotros llamamos a la clase lo cual repercute en la escalabilidad y el desempeño de la aplicación si se tuvieran que invocar decenas o cientos las ejecuciones a esta clase.


A continuación el programa principal:

using System;
using System.Collections.Generic;
using System.Linq;

namespace PostSingleton
{
public class Program
{
static List _conns = null;
public static int Main(string[] args)
{
_conns = new List();
string op = null;
Console.ForegroundColor = ConsoleColor.White;
do{
Console.Write("\n");
Console.WriteLine("+-------------------------------+");
Console.WriteLine(" Ejemplo del patron singleton para conexiones");
Console.Write("\n");
Console.WriteLine("a) Conexión DB");
Console.WriteLine("b) Ver Conexiones");
Console.WriteLine("q) Salir");
Console.Write("\n");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("Elija su opción y pulse : ");
Console.ForegroundColor = ConsoleColor.White;
op = Console.ReadLine().ToLower();
switch(op){
case "a":
ConectarDB();
break;
case "b":
VerConexiones();
break;
}
}while(op != "q");
Console.WriteLine("\nHasta luego");
return 0;

}
static void VerConexiones(){
try{
Console.Clear();
Console.WriteLine("\nListado de conexiones");
Console.Write("\n");
Console.WriteLine("+------------------------------------+");
Console.WriteLine("| CONEXIONES ACTIVAS |");
Console.WriteLine("+------------------------------------+\n");
if(_conns.Count > 0){
var q = from c in _conns where c.IsOpen == true select c;
foreach(var i in q){
Console.WriteLine("{0}",i.Info);
}}else Console.WriteLine("NO HAY CONEXIONES ACTIVAS");
}catch(Exception x){ Console.WriteLine("Excepcion " + x.Message); }
}
static void ConectarDB(){
try{
Console.Clear();
Console.WriteLine("Datos de la cadena de conexion ");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("Servidor y pulse : ");
string server = @Console.ReadLine();
Console.Write("Base de datos y pulse : ");
string database = @Console.ReadLine();
Console.Write("Usuario y pulse : ");
string user = @Console.ReadLine();
Console.Write("Password y pulse : ");
string password = @Console.ReadLine();
Console.ForegroundColor = ConsoleColor.White;
string connStr = String.Format(
"Data Source={0};Initial Catalog={1};User ID={2};Password={3};",
server,database,user,password);
Console.WriteLine("Intentando conexión...");
DataBase db = new DataBase(connStr);
_conns.Add(db);
VerConexiones();
}catch(Exception x){
Console.WriteLine("Excepción " + x.Message);
}
}
static void Exit(){
Environment.Exit(0);
}}}

Al compilar y ejecutar la aplicación se mostrará el siguiente menú.

Escogiendo la opción (a) nos mostrará el menú para solicitarnos los parámetros de la cadena de conexión, si repetimos este procedimiento nos mostrará
las conexiones hechas hacia el servidor, una por cada vez que hayamos completado la opción (a) como se muestra en la siguiente imagen.



Observamos en la imagen como es diferente el tiempo entre cada una de las conexiones ya que se crea una conexión por cada llamado.



Bien ahora mostraremos el mismo ejercicio utilizando el patrón Singleton en el código de la clase DataBase, pero para no sobrescribir la clase DataBase del ejercicio anterior, nombraremos la clase Singleton como DataBase2.



Analizamos la clase y vemos el uso de los modificadores private y static en el constructor hace que no se pueda crear la clase de forma directa, sino solo a traves del método public GetInstance(string conStr) que regresa la instancia creada y por ende sus propiedades y métodos públicos.
Antes de ejecutar el programa principal para que utilice la clase con el singleton, hay que modificar la líneas donde se crea la lista de conexiones

static List _conns = null;
_conns = new List();

y tambien donde se invoca la conexión con la base de datos.

_conns.Add(DataBase2.GetInstance(connStr));

Haciendo estos cambios, ejecutando la aplicación, seleccionando la opción (a) para conectarse a una base de datos y creando varias conexiones debemos de ver
la salida del programa como en la siguiente pantalla:

Observamos en la imagen como el tiempo entre cada una de las conexiones es siempre el mismo, ya que se crea una sola instancia global de acceso.

 Descarga el código fuente