viernes, septiembre 10, 2010

Desarrollo Aplicación N-Capas para Windows Mobile ( II )

Hola a tod@s nuevamente, hoy vamos a hablar como implementar este modelo de N-Capas en nuestra aplicación.

 

Tomando nuestro mismo ejemplo del articulo “Operaciones CRUD con SQL Mobile y ADO.NET en Windows Mobile” que lo pueden encontrar en  este enlace. Y aplicando la estructura de N-Capas del articulo anterior, aquí lo pueden consultar.

 

Implementando N-Capas en Visual Studio 2008

Lo primero es crear una solución en VS2008 que vamos a llamar WMBDNNCapas, y el tipo de proyecto a seleccionar es un proyecto Windows Mobile Application (Aplicación de Dispositivo).

 

image

Como se puede observar en al imagen, seleccionamos la plataforma de destino para la cual vamos a desarrollar, en este caso "WM 6 Professional SDK” y la versión del Compact Framework para la cual vamos a desarrollar: 3.5.

 

Este proyecto de tipo aplicación Windows, es nuestra capa superior o capa de presentación.

Ahora vamos a proceder a crear 4 proyectos de tipo librería de clases, que representen las capas de Negocio (BL 0 Business Logic), Manejo de Datos (DM = Data Management), Acceso a Datos (DA = Data Access) y la capa de Infraestructura Transversal (Entities).  Los datos entre paréntesis, son los sufijos de los nombres de los proyectos que vamos a crear y los cuales indicaran cada una de las diferentes capas del modelo N-Capas a desarrollar.

Mi practica personal es utilizar el mismo nombre del proyecto principal, y agregarle el sufijo indicado en los paréntesis a los diferentes proyectos a crear.

En otras palabras voy a crear un proyecto de tipo librería de clases llamado WMBDNNCapasBL que representa la capa lógica, un proyecto de tipo librería de clases llamado WMBDNNCapasDM que representa la capa de manejo de datos, un proyecto de tipo librería de clases llamado WMBDNNCapasDA que represente el acceso a los datos y por último un proyecto de tipo librería de clases llamado WMBDNNCapasEntities que representa la capa de las entidades y colecciones donde se transportan los datos entre las diferentes capas del modelo.

 

Para crear los diferentes proyectos y adicionarlos a la solución que ya hemos creado, para esto, damos clic derecho en el nombre de la solución y en menú contextual que aparece, seleccionamos Agregar y Nuevo proyecto…

image

Le damos el nombre al proyecto y lo configuramos de la manera correcta:

image

Después de crear todos los proyectos en la solución, nuestra solución quedaría de la siguiente manera:

image

 

Capa de Acceso a Datos

La primera capa que vamos a desarrollar es la capa de Acceso a Datos, o sea el proyecto WMBDNNCapasDA, este proyecto en nuestro caso solo va a contener 1 clase para el manejo al acceso de la bases de datos tipo SQL Mobile, en algunos casos de aplicaciones móviles he tenido la necesidad de manejar varios tipos de bases de datos, en ese caso en este proyecto existe mas de una clase para el manejo y acceso a los datos.

image

Lo primero es eliminar del proyecto la clase que se crea por defecto Class1.cs , luego creamos una nueva clase a la cual le vamos a signar el nombre DBSQLMobileDA.cs.

Si se fijan como regla tengo que a las clases también les coloco el mismo sufijo que utilizo en el proyecto.

Lo siguiente que vamos  a hacer es agregar la referencia para System.Data.SqlCeServer que es la clase que me permite acceder a bases de datos Microsoft SQL Mobile.

Para esto debemos dar clic derecho sobre la carpeta de References del proyecto, y escogemos Agregar Referencia:

image

Al hacer esto Visual Studio nos muestra una ventana con la lista de las referencias que podemos utilizar para nuestro proyecto:

image

Buscamos en la lista System.Data.SqlServerCe y lo seleccionamos, presionamos el botón Aceptar para asegurar esta selección.

Al hacer esto la lista de las referencias se actualiza y debe aparecer de la siguiente manera:

image

Como observamos la referencia fue adicionada a la lista.

Aquí es muy importante resaltar que esta referencia solo se realizara en este proyecto,NO se realizara en los demás proyectos, pues solo este proyecto es el único que interactúa de manera directa con la base de datos.

Si en nuestra solución necesitamos de otra referencia a una base de datos diferente, se agregará la nueva referencia también en este proyecto y en ningún otro de la solución.

Esto es súper importante en la arquitectura de N-Capas, porque estamos aislando en las diferentes capas las funcionalidades, en este caso particular la capa de acceso a la base de datos.

Muy bien, ya entendiendo esto, vamos a codificar nuestra clase de conexión y de interactuación directa con la base de datos y sus objetos.

 

Implementar Clase de Conexión con la base de Datos

Lo primero es en nuestra clase colocar la palabra public para que esta clase sea publica y la podamos utilizar.

public class DBSQLMobileDA





El primer método a desarrollar es el método Open, este método abre una conexión a la base de datos, además verifica si ya esta abierta la conexión no realiza la operación.



A esta clase debemos indicar al principio de esta los using que vamos a utilizar:



using System.Data.SqlServerCe;



Lo primero que vamos a hacer es crear una propiedad para la Conexión pues es posible que necesitemos pasar la conexión de un método a otro.



        /// <summary>Propiedad que almacena el objeto de Conexion a la BD
/// </summary>
public SqlCeConnection Conexion { get; set; }


 



Además debemos crear otra propiedad de tipo String para almacenar la ruta en la cual va a estar el archivo .sdf con la base de datos.



        /// <summary> Ruta en donde va a quedar la base de datos
/// </summary>
public String Ruta { get; set; }


 



Esta sintaxis es para el Compact Framework 3.5, recuerden estas son propiedades auto implementadas del lenguaje C#, para Visual Basic.NET esto solo es posible con el Framework .NET 4.0.



Algo que debemos hacer es inicializar esta propiedad en el constructor de la clase:



        public DBSQLMobileDA()
{
Conexion = new SqlCeConnection();
}



Y ahora si nuestro método de conectarse a la base de datos:



        /// <summary>Metodo que abre la conexion a la Base de datos
/// </summary>
public void Open()
{
// Si hay una conexion abierta la mantengo
if (Conexion.State == System.Data.ConnectionState.Open)
return;

// Armo la cadena de conexion
Conexion.ConnectionString = "Data Source=" + Ruta + "DemoBD.sdf;";

// Abro la conexion
try
{
Conexion.Open();
}
catch (SqlCeException ex)
{
throw ex;
}
}



En el código verificamos si ya la conexión esta abierta y salimos del método, si no está abierta, le asignamos la cadena de conexión al objeto de conexión y llamamos al método Open().



En la propiedad Ruta, vamos a tener la ruta del sistema de archivos en el cual esta el archivo de la base de datos, y de esa manera armamos la cadena de conexión.



Vamos a crear un método que es el que inicializa el objeto comando y es el que necesitamos para ejecutar todas las operaciones necesarias de la base de datos.



Este método lo vamos a llamar CreateComando, para esto también necesitamos una propiedad de tipo SqlCeCommand que vamos a llamar Comando.



La propiedad seria:



        /// <summary>Propiedad que devuelve un objeto SqlCeCommand
/// </summary>
public SqlCeCommand Commando { get; set; }




Y el código del método CreateComando es el siguiente:



        /// <summary>Crea un Objeto SqlCeCommand para ser utilizado
/// </summary>
public void CreateComando()
{
try
{
Commando = Conexion.CreateCommand();
}
catch (Exception ex)
{
throw ex;
}
}



Simplemente lo que hace este método es inicializar el objeto SqlCeCommand y a través de él manejar las diferentes operaciones contra la base de datos.



Ahora vamos a crear un método que me permita leer o extraer datos de la base datos, nuestro método se llama ExecuteReader, pues los datos nos los va a devolver en un IDataReader, esto nos asegura que la lectura de los datos va a ser bastante rápida.



Lo primero es crear la propiedad de tipo IDataReader, para esto necesitamos también tener el using System.Data:



        /// <summary>Propiedad que Expone el DataReader en donde se encuentran los datos leidos
/// </summary>
public IDataReader DataReader;



 



Y el código del método ExecuteReader es el siguiente:



        /// <summary>Ejecuta sentencias SQL en la BAse de datos SQL Mobile
/// </summary>
/// <param name="tipoComando">Un CommandType para saber que se hace con la instruccion</param>
/// <param name="query">La sentencia SQL a Ejecutar</param>
/// <returns>Un Datareader para ser recorrido</returns>
public IDataReader ExecuteReader(CommandType tipoComando, String query)
{
DataReader = null;
Commando.Connection = Conexion;
Commando.CommandType = tipoComando;
Commando.CommandText = query;

try
{
DataReader = Commando.ExecuteReader();
}
catch (SqlCeException ex)
{
throw ex;
}

return DataReader;
}



Este método recibe dos parámetros, uno es el tipo de comando a ejecutar, y el otro una cadena con la sentencia SQL a ejecutar, se le asigna al objeto Commando la Conexión, el tipo de comando y la sentencia a ejecutar, luego en bloque try.. catch de ejecuta la sentencia llamando al método ExecuteReader del objeto SqlCeCommand.



El método devuelve un objeto IDataReader con los datos que devuelve al base de datos.



Por último tenemos el método ExecuteNonQuery para ejecutar las sentencias SQL que afectan  los datos en la tabla de la base de datos.



        /// <summary> Ejecuta sentencias de INSERT, DELETE y UPDATE 
/// </summary>
/// <param name="tipoComando">Tipo de comando a Ejecutar</param>
/// <param name="query">Instruccion SQL a Ejecutar</param>
/// <returns>Un entero con el numero de registros Afectados</returns>
public Int32 ExecuteNonQuery(CommandType tipoComando, String query)
{
Commando.Connection = Conexion;
Commando.CommandType = tipoComando;
Commando.CommandText = query;
Int32 stReturn;

try
{
stReturn = Commando.ExecuteNonQuery();
}
catch (SqlCeException ex)
{
throw ex;
}

return stReturn;
}



El código completo de nuestra clase es el siguiente:




using System;


using System.Linq;


using System.Collections.Generic;


using System.Text;


using System.Data.SqlServerCe;


using System.Data;


 


namespace WMBDNNCapasDA


{


    public class DBSQLMobileDA


    {


        #region Propiedades


 


        /// <summary>Propiedad que almacena el objeto de Conexion a la BD


        /// </summary>


        public SqlCeConnection Conexion { get; set; }


        /// <summary> Ruta en donde va a quedar la base de datos


        /// </summary>


        public String Ruta { get; set; }


        /// <summary>Propiedad que devuelve un objeto SqlCeCommand


        /// </summary>


        public SqlCeCommand Commando { get; set; }


        /// <summary>Propiedad que Expone el DataReader en donde se encuentran los datos leidos


        /// </summary>


        public IDataReader DataReader;


 


        #endregion


 


 


        public DBSQLMobileDA()


        {


            Conexion = new SqlCeConnection();


            Commando = new SqlCeCommand();


        }


 


 


        /// <summary>Metodo que abre la conexion a la Base de datos


        /// </summary>


        public void Open()


        {


            // Si hay una conexion abierta la mantengo


            if (Conexion.State == System.Data.ConnectionState.Open)


                return;


 


            // Armo la cadena de conexion


 


            Conexion.ConnectionString = "Data Source=" + Ruta + "DemoBD.sdf;";


 


            // Abro la conexion


            try


            {


                Conexion.Open();


            }


            catch (SqlCeException ex)


            {


                throw ex;


            }


        }


 


 


        /// <summary>Crea un Objeto SqlCeCommand para ser utilizado


        /// </summary>


        public void CreateComando()


        {


            try


            {


                Commando = Conexion.CreateCommand();


            }


            catch (Exception ex)


            {


                throw ex;


            }


        }


        /// <summary>Ejecuta sentencias SQL en la BAse de datos SQL Mobile


        /// </summary>


        /// <param name="tipoComando">Un CommandType para saber que se hace con la instruccion</param>


        /// <param name="query">La sentencia SQL a Ejecutar</param>


        /// <returns>Un Datareader para ser recorrido</returns>


        public IDataReader ExecuteReader(CommandType tipoComando, String query)


        {


            DataReader = null;


            Commando.Connection = Conexion;


            Commando.CommandType = tipoComando;


            Commando.CommandText = query;


 


            try


            {


                DataReader = Commando.ExecuteReader();


            }


            catch (SqlCeException ex)


            {


                throw ex;


            }


 


            return DataReader;


        }


 


        /// <summary> Ejecuta sentencias de INSERT, DELETE y UPDATE 


        /// </summary>


        /// <param name="tipoComando">Tipo de comando a Ejecutar</param>


        /// <param name="query">Instruccion SQL a Ejecutar</param>


        /// <returns>Un entero con el numero de registros Afectados</returns>


        public Int32 ExecuteNonQuery(CommandType tipoComando, String query)


        {


            Commando.Connection = Conexion;


            Commando.CommandType = tipoComando;


            Commando.CommandText = query;


            Int32 stReturn;


 


            try


            {


                stReturn = Commando.ExecuteNonQuery();


            }


            catch (SqlCeException ex)


            {


                throw ex;


            }


 


            return stReturn;


        }


 


    }


}




 



Resumen



En resumen :



Esta clase que hemos creado solo se encarga y esta especializada en la conexión a la base de datos y de ejecutar las diferentes operaciones contra la base de datos, de esta manera aislamos en esta capa y específicamente en esta clase las diferentes operaciones contra la base de datos.



Nuestra clase tiene los siguientes métodos:




  • Open: que establece la conexión con la base de datos.


  • CreateComando: que inicializa el objeto SqlCeCommand para las diferentes operaciones a realizar.


  • ExecuteReader: que ejecuta una sentencia contra la base de datos y devuelve un conjunto de registros en un objeto IDataReader.


  • ExecuteNonQuery: que ejecuta sentencias contra la base de datos para afectar los datos.



Podemos incluir algunos otros métodos que consideremos necesarios, como por ejemplo para controlar una transacción, si definitivamente necesitamos devolver datos en un objeto DataTable pues también podemos crear un método que nos devuelva este tipo de objeto.



Si necesitamos una conexión a una base de datos diferente, crearemos una nueva clase para el manejo de esta y agregaremos la referencia necesaria para que esto funcione, los métodos deberían ser los mismos que hemos desarrollado en esta clase.



 



En el próximo artículo veremos como utilizar esta clase y esta capa con la capa de manejo de datos.



Espero que haya sido lo suficientemente explicito en esta clase y si tienen preguntas no duden en colocarlas aquí en el blog para responderlas.



 



Enjoy develop!



 



Hasta la próxima!!!!