Hola ¿Qué tal?...
En esta ocasión continuando con la propuesta de arquitectura que comenté en el último artículo de arquitectura (http://msmvps.com/blogs/otelis/archive/2008/01/08/hablemos-de-arquitectura-de-software.aspx) quiero comenzar por establecer primeramente las directrices basadas enteramente en el documento titulado “Application Architecture for .NET: Designing Applications and Services” (http://msdn2.microsoft.com/en-us/library/ms954595.aspx). En principio estaré enfocado al capítulo 2 de este documento para definir simplemente la base de esta propuesta.
Considerando que encontramos tres grandes grupos de componentes, divididos en Presentación, Negociación y Datos, quisiera empezar primeramente por la parte más baja, donde encontramos a los datos, para iniciar desde ahí. El por qué empezar desde este punto es por definición de donde continúa la construcción de una aplicación, donde primeramente se diseña la base de datos y en seguida se construye la aplicación.
De acuerdo a las recomendaciones, cada tabla de la base de datos debe corresponderse con un componente de acceso a datos, en mi percepción, genero un componente de acceso a datos por tabla siguiendo ciertos criterios que posteriormente mostraré. Inicialmente, debo definir un DataHelper, que será el encargado de establecer la conexión con la base de datos, y que será dónde la conexión se administre y viva, ahí se ejecutará cualquier acción dirigida a la base de datos, acciones como, consultas, modificaciones y hasta alteraciones a la estructura de la base de datos, así pues, debemos entender que la conexión con la base de datos solo estará en este componente, solo en el Helper y en ninguna otra parte. La definición en el modelo que propongo será sobre una clase abstracta y deberá ser heredada en cada componente de acceso a datos. El criterio para definirla abstracta, es porque no debe ser instanciada de forma directa, así los componentes de acceso a datos serán quienes tengan la capacidad de exponer la funcionalidad con la base de datos totalmente específica de cada uno de estos de un modo íntimo y discreto, exponiendo únicamente los métodos que le concierne a los componentes que los consuman.
Este Helper contará con el soporte de una interfaz cuya función será propagar la información necesaria para conectarse a la base de datos, esto es, la información básica de usuario, servidor, base de datos y contraseña, con esta interfaz podremos inicializar el helper y darle capacidad de interactuar con la base de datos. Esta información se propagará en el constructor de cada componente de acceso a datos que se derive del helper. Es importante mencionar que esta interfaz es la chispa de vida de cada componente de acceso a datos y que sin ella nada funcionará.
Entonces, teniendo en cuenta esto podemos empezar a definir la estructura de nuestro helper. Veamos entonces de una buena vez cómo definimos la clase de este componente.
VB
Namespace DataHelper
Public MustInherit Class SqlDataHelper
Public Sub New(ByVal sqlSet As DBInfo.IDbSettings)
End Sub
End Class
End Namespace
C#
namespace DataHelper
{
public abstract class SqlDataHelper
{
public SqlDataHelper(DBInfo.IDbSettings sqlSet)
{
}
}
}
La interfaz que sirve de apoyo al transporte de la información de conexión de la base de datos estaría definida de la siguiente manera:
VB
Namespace DBInfo
Public Interface IDbSettings
Property Server() As String
Property DataBase() As String
Property User() As String
Property Password() As String
Function GetConnectionString() As String
End Interface
End Namespace
C#
namespace DBInfo
{
public interface IDbSettings
{
string Server{get;set;}
string DataBase{get;set;}
string User{get;set;}
string Password{get;set;}
string GetConnectionString();
}
}
Nótese que se tienen dos espacios de nombre, el primero totalmente relacionado al DataHelper y el segundo relacionado a información de la Base de Datos, he decidido dejarlos separados para no mezclar conceptos.
Ahora bien, ya definimos la clase y la interfaz de información de conexión, sin embargo, habrá todavía más que hacer, empezaré terminando con la definición básica del DataHelper, el cual es alusivo a SQL Server; por cierto.
Lo siguiente será definir la funcionalidad del constructor, y declarar la variable de conexión con la que se trabajará en las operaciones relacionadas con el mismo apuntando a una base de datos.
Inicialmente debemos declarar una variable del tipo SqlConnection, para utilizarla en todo el helper, utilizaremos varias variables adicionales para devolver los mensajes que se generen dentro de cada método del helper, además de los mensajes nativos del servidor y los números de error en caso de que se presenten y por si fuera poco, también una variable que indique si la conexión es buena o no y una variable para almacenar la información de conexión para tenerla disponible en todo momento dentro del helper. Así pues tendremos las siguientes declaraciones iníciales:
VB
Public MustInherit Class SqlDataHelper
Private cnnHelper As SqlConnection
Private mMessageHelper As String
Private mMessageServer As String
Private mErrorNumber As Integer
Private mIsValidConnection As Boolean
Private mSqlSettings As IDbSettings
Public Sub New(ByVal sqlSet As DBInfo.IDbSettings)
End Sub
End Class
C#
public abstract class SqlDataHelper
{
private SqlConnection cnnHelper;
private string messageHelper;
private string messageServer;
private int errorNumber;
private bool isValidConnection;
private IDbSettings sqlSettings;
public SqlDataHelper(DBInfo.IDbSettings sqlSet)
{
}
}
Continuando con el constructor, instanciaremos la variable de conexión, además deberemos verificar que la conexión es válida para no caer en errores de conexión al intentar utilizar algún método de nuestro helper, por lo que definiremos un método para esta tarea. Al verificar la valides de la conexión podremos agregar un manejador para el evento que devuelve información del servidor cada que se utiliza la conexión. Este evento es el denominado InfoMessage de la conexión. No nos olvidemos del método manejador del evento InfoMessage de la conexión. Quedando la clase de esta manera:
VB
Public MustInherit Class SqlDataHelper
Private cnnHelper As SqlConnection
Private mMessageHelper As String
Private mMessageServer As String
Private mErrorNumber As Integer
Private mIsValidConnection As Boolean
Private mSqlSettings As IDbSettings
Public Sub New(ByVal sqlSet As DBInfo.IDbSettings)
mSqlSettings = sqlSet
cnnHelper = New SqlConnection()
If IsValidConnection() Then
AddHandler cnnHelper.InfoMessage, _
AddressOf cnnHelper_InfoMessage
End If
End Sub
Private Sub cnnHelper_InfoMessage( _
ByVal sender As Object, _
ByVal e As SqlInfoMessageEventArgs)
mMessageServer = e.Message
End Sub
Private Function IsValidConnection() As Boolean
mErrorNumber = 0
If cnnHelper.State = ConnectionState.Open Then
cnnHelper.Close()
End If
cnnHelper.ConnectionString = mSqlSettings.GetConnectionString()
Try
If Not IsValidConnection Then
cnnHelper.Open()
cnnHelper.Close()
End If
mIsValidConnection = True
mMessageHelper = "Conexión exitosa"
Catch ex As SqlException
mIsValidConnection = False
mErrorNumber = ex.Number
mMessageHelper = ex.Message
End Try
Return mIsValidConnection
End Function
End Class
C#
public abstract class SqlDataHelper
{
private SqlConnection cnnHelper;
private string messageHelper;
private string messageServer;
private int errorNumber;
private bool isValidConnection;
private IDbSettings sqlSettings;
public SqlDataHelper(DBInfo.IDbSettings sqlSet)
{
sqlSettings = sqlSet;
cnnHelper = new SqlConnection();
if (IsValidConnection())
{
cnnHelper.InfoMessage +=
new SqlInfoMessageEventHandler(cnnHelper_InfoMessage);
}
}
private void cnnHelper_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
messageServer = e.Message;
}
private bool IsValidConnection()
{
errorNumber = 0;
if (cnnHelper.State == ConnectionState.Open)
cnnHelper.Close();
cnnHelper.ConnectionString = sqlSettings.GetConnectionString();
try
{
if (!isValidConnection)
{
cnnHelper.Open();
cnnHelper.Close();
}
isValidConnection = true;
messageHelper = "Conexión exitosa";
}
catch (SqlException ex)
{
isValidConnection = false;
errorNumber = ex.Number;
messageHelper = ex.Message;
}
return isValidConnection;
}
}
Como podrá notarse el método manejador el evento InfoMessage es muy simple, solo tiene que pasarse el valor del mensaje del servidor a nuestra variable de mensaje de servidor, por otra parte, el método validador de la conexión, utiliza la variable isValidConnection (mIsValidConnection en VB) para no intentar nuevamente la conexión si esta es válida. La cadena de conexión para la variable cnnHelper se toma del método GetConnectionString() de la variable sqlSettings (mSqlSettings en VB) que se encarga de generar la cadena de conexión en base a los parámetros establecidos en las variables de conexión.
Hasta aquí, tenemos ya la primera parte del DataHelper, y los instrumentos que se utilizarán a través de los métodos subsecuentes del helper. La funcionalidad básica será adicionada a esta clase método por método según las necesidades de funcionalidad para con la base de datos.
Antes de continuar, terminemos el complemento de las variables declaradas a nivel de clase con las propiedades correspondientes, mismas que serán de utilidad para exponer lo que sucede dentro del helper hacia el exterior, para informes o toma de decisiones. Debemos tener en cuenta que como los valores de las variables se asignan dentro del helper las propiedades tendrán que ser de solo lectura a modo de propiedades informativas. Así pues, agreguemos las siguientes propiedades:
VB
Public ReadOnly Property SqlSettings() As IDbSettings
Get
Return mSqlSettings
End Get
End Property
Public ReadOnly Property ErrorNumber() As Integer
Get
Return mErrorNumber
End Get
End Property
Public ReadOnly Property MessageHelper() As String
Get
Return mMessageHelper
End Get
End Property
Public ReadOnly Property MessageServer() As String
Get
Return mMessageServer
End Get
End Property
C#
public IDbSettings SqlSettings
{
get
{
return sqlSettings;
}
}
public int ErrorNumber
{
get
{
return errorNumber;
}
}
public string MessageHelper
{
get
{
return messageHelper;
}
}
public string MessageServer
{
get
{
return messageServer;
}
}
Por el momento será todo para la primera parte, en la segunda parte terminaremos con la definición del data helper, pero aún faltará subir un peldaño con la definición del Data Access Component, así que tendremos que ir un poco más rápido con los temas para no perder la continuidad.
Pues bien, nos estaremos viendo en el siguiente post.
La liga para descarga de los archivos relacionados con este artículo:
http://code.msdn.microsoft.com/datahelper
Continuar con la siguiente parte:
http://msmvps.com/blogs/otelis/archive/2009/03/15/arquitectura-definici-243-n-de-un-datahelper-parte-2.aspx
Saludos…
Octavio Telis