abril 17, 2007

Ejemplo de una Aplicación ASP.NET 2.0 en 3 capas con Colecciones de Objetos Personalizados

Para el desarrollo de esta aplicación utilizamos Visual Basic .NET con Visual Studio .NET 2005.
La arquitectura es en 3 capas con uso del patrón Mapper.

Estrucutura del proyecto ASP.NET
- Una carpeta App_Code con 3 carpetas.

  • La Carpeta Entities. Esta carpeta contiene a todos las clases que corresponden a los objetos de negocio del tipo entity, es decir objetos persistentes en la Base de Datos

  • La Carpeta ColeccionesObj. Esta carpeta contiene a las clases que operan como colecciones de objetos de los objetos entity, es decir existe un objeto collecion por cada objeto Entity.

  • La Carpeta Mappers. Esta carpeta contiene a las clases encargadas de crear objetos entity uno o más con los registros que obtiene de la base de datos y los objetos creados son consumidos por la capa de presentación. Los objetos mappers contienen los métodos necesarios para obtener y persistir los objetos del tipo Entity. Para cada objeto entity existe un objeto Mapper, pero cada uno de estos tiene el patrón Singleton para asegurar que exista una única instancia en toda la aplicación. Podriamos decir que este objeto es el encargado del acceso a datos y hace uso las objetos entity que devueve a la capa de presentación.









-La forma Web “Area.aspx” representa a la capa GUI

Las 3 capas

En una arquitectura en 3 capas tenemos la capa de presentación o GUI, en nuestro ejemplo son los archivos aspx. La capa de Negocio que en nuestro ejemplo la representan nuestras clases Entity ubicados en la carpeta Entites y la capa de Acceso a Datos representada por los objetos Mappers en nuestra carpeta Mappers y la Capa de datos son los objetos de la Base de Datos en nuestro ejemplo se representa con store procedures. En este caso los objetos Mappers son los encargados de comunicar las 3 capas y pasar datos del mundo relacional al de objetos.


















Detalles de la Implementación

Tenemos una tabla llamada Area para la cual queremos implementar una forma de mantenimiento. La pantalla a la que queremos dar funcionalidad con la arquitectura en 3 capas es:






















Esta es la estructura de a tabla de la base de dato correspondiente al Area y los datos que regresa el store procedure que estaremos ejecutando.























Implementación de la clase Entity (Objeto de Capa de Negocio)

Algunas de las formas de representar a los Business Entities en la aplicación son:
· XML
· DataSet Genericos
· DataSet Tipados
· Componentes Business Entities personaizados
· Componentes Business Entities con comportamiento CRUD



Para nuestro ejemplo utilizaremos el caso de ”Componentes Business Entities Personalizados”.

La clase Entity representa al objeto de negocio Area. Para ello agregamos una Clase en la carpeta Entities con el nombre AreaBLL.

Imports Microsoft.VisualBasic

Public Class AreaBLL

Private _idArea As Integer
Private _nombreArea As String
Private _obsArea As String
Private _esActivaArea As Boolean
Private _fechaModificArea As Date
Private _usrModificArea As String
Private _idAreaPadre As Integer
Private _AreaPadre As String

Public Property IdArea() As Integer
Get
Return Me._idArea
End Get
Set(ByVal value As Integer)
Me._idArea = value
End Set
End Property

Public Property NombreArea() As String
Get
Return Me._nombreArea
End Get
If value.Trim.Length > 0 Then
Me._nombreArea = value
Else
Throw New Exception("Debe proporcionar el nombre del área")
End If
End Property

Public Property ObsArea() As String
Get
Return Me._obsArea
End Get
Set(ByVal value As String)
Me._obsArea = value
End Set
End Property

Public Property EsActivaArea() As Boolean
Get
Return Me._esActivaArea
End Get
Set(ByVal value As Boolean)
Me._esActivaArea = value
End Set
End Property

Public Property FechaModificArea() As Date
Get
Return Me._fechaModificArea
End Get
Set(ByVal value As Date)
Me._fechaModificArea = value
End Set
End Property

Public Property UsrModificArea() As String
Get
Return Me._usrModificArea
End Get
Set(ByVal value As String)
Me._usrModificArea = value
End Set
End Property

Public Property IdAreaPadre() As Integer
Get
Return Me._idAreaPadre
End Get
Set(ByVal value As Integer)
Me._idAreaPadre = value
End Set
End Property

Public Property AreaPadre() As String
Get
Return Me._AreaPadre
End Get
Set(ByVal value As String)
Me._AreaPadre = value
End Set
End Property

End Class

Podemos observar que se compone de propiedades privadas que representan a cada una de las columnas de la tabla. Para que dichas propiedades sean accesibles creamos los métodos públicos que leen o escriben en las propiedades. (Con esto implementamos el concepto de Encapsulamiento de la teoría de la Programación Orientada a Objetos).

Implementación de la clase colección para cada objeto Entity

Ahora requerimos construir una clase que nos permita contener una colección de objetos entidad. Si observamos la pantalla que deseamos dar funcionalidad tenemos una rejilla que debe poblarse con objetos entidad del tipo AreaBLL. Agregamos una clase que llamaremos Area_Coleccion y que debe heredar de la clase CollectionBase.

Imports Microsoft.VisualBasic

Public Class Area_Coleccion
Inherits CollectionBase
Default Public Property Item(ByVal index As Integer) As AreaBLL
Get
Return CType(List(index), AreaBLL)
End Get
Set(ByVal value As AreaBLL)
List(index) = value
End Set
End Property

Public Function Add(ByVal value As AreaBLL) As Integer
Return (List.Add(value))
End Function

Public Function IndexOf(ByVal value As AreaBLL) As Integer
Return (List.IndexOf(value))
End Function

Public Sub Insert(ByVal index As Integer, ByVal value As AreaBLL)
List.Insert(index, value)
End Sub

Public Sub Remove(ByVal value As AreaBLL)
List.Remove(value)
End Sub

Public Function Contains(ByVal value As AreaBLL) As Boolean
Return (List.Contains(value))
End Function
End Class

Podemos observar que los métodos de esta clase reciben objetos del tipo Area. Es así que para cada objeto Entity que tengamos debemos crear un objeto Colección, esto si es que requerimos devolver una colección de objetos a la capa de datos. En nuestro ejemplo si requerimos poblar un GridView que muestra a un conjunto de objetos Area.

Implementación de la clase Mapper para cada objeto Entity

Esta es la clase que se encarga de regresar un objeto Entity a la capa de presentación o una colección de objetos de acuerdo al método invocado.

Como esta clase es la que accede a la base de datos utilizamos el DataBlock de Microsoft. Accedemos a los datos a través de store procedures. La cadena de conexión se encuentra en el archivo web.config


Si observamos el método “GetAllArea” retorna una colección de objetos del tipo Area_Colección. Se extraen los registros de base de datos a través de un SqlDataReader y luego se recorre a cada uno y con cada renglon se pobla un objeto Entity AreaBLL, luego el objeto poblado se agrega a la Colección de objetos Area y así sucesivamente para cada objeto creado de acuerdo a los registros de base de datos obtenidos en el SqlDataReader.

Imports Microsoft.VisualBasic
Imports Microsoft.ApplicationBlocks.Data
Imports System.Data.SqlClient
Imports System.Reflection
Imports System.Data

Public Structure AreaMapper
Private _SQLCon As String

'Propiedades necesarias para implementar la clase como Singleton.
Private Shared mInstance As AreaMapper
Private Shared mMutex As New System.Threading.Mutex()

Public ReadOnly Property SQLCon() As Integer
Get
Return Me._SQLCon
End Get
End Property

'Implementando la clase como Singleton.
Public Shared Function GetInstance() As AreaMapper
mMutex.WaitOne()
If mInstance Is Nothing Then
mInstance = New AreaMapper()
End If
mMutex.ReleaseMutex()
Return mInstance
End Function

Public Sub New()
_SQLCon = ConfigurationManager.ConnectionStrings("TimonConnectionString").ToString()
End Sub

'Iniciar con la cadena de conexión
Sub New(ByVal pSQLCon As String)
_SQLCon = pSQLCon
End Sub

Public Function GetAllArea() As Area_Coleccion
Dim dr As SqlDataReader = Nothing
Try
dr = SqlHelper.ExecuteReader(_SQLCon, Data.CommandType.StoredProcedure, "spSelectArea")
Dim ListaAreas As New Area_Coleccion
While dr.Read()
ListaAreas.Add(PopulateArea(dr))
End While
Return ListaAreas

Catch ex As SqlException
Throw New Exception(ex.Message & " En la rutina: " & MethodInfo.GetCurrentMethod.Name)
Catch ex As Exception
Throw New Exception(ex.Message & " En la rutina: " & MethodInfo.GetCurrentMethod.Name)
Finally
If Not dr Is Nothing AndAlso Not dr.IsClosed Then
dr.Close()
End If
End Try
End Function

Private Function PopulateArea(ByVal dr As SqlDataReader) As AreaBLL
Dim ObjArea As New AreaBLL
Try

ObjArea.IdArea = Convert.ToInt32(dr(0)) 'IdArea
ObjArea.NombreArea = Convert.ToString(dr(1)) 'NombreArea

'ObsArea
If Not dr(2) Is DBNull.Value Then
ObjArea.ObsArea = Convert.ToString(dr(2))
End If

'EsActivaArea
ObjArea.EsActivaArea = Convert.ToByte(dr(3))
'AreaPadre
ObjArea.AreaPadre = Convert.ToString(dr(4))

Return ObjArea

Catch ex As SqlException
Throw New Exception(ex.Message & "En la rutina: " & MethodInfo.GetCurrentMethod.Name)
Catch ex As Exception
Throw New Exception(ex.Message & "En la rutina: " & MethodInfo.GetCurrentMethod.Name)
End Try
End Function


End Structure



Implementación de la capa de Presentación GUI

En esta capa es en donde vamos a poblar los controles visuales con objetos Entity o listas de objetos Entity. Nosotros queremos que la cargarse la forma web se poble el GridView con los datos de todas las áreas que se encuentran en la tabla Area de la base de datos. Hacemos esto en el evento Load. Podemos observar como creamos un objeto de la clase AreaMapper y que para poblar el GridView ejecutamos su método GetAllArea y que lo establecemos como DataSource al GridView a esto se lo conoce como DataBinding con objetos de negocio.

Partial Class _Default
Inherits System.Web.UI.Page

Private ObjAreaMapper As AreaMapper

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
ObjAreaMapper = AreaMapper.GetInstance()
Call poblarDBGrid()
Call poblarListaAreasPadre()

End If
End Sub

Private Sub poblarDBGrid()
Try
Me.GridView1.DataSource = ObjAreaMapper.GetAllArea
Me.GridView1.DataBind()
Me.LabelTotalRegGrid.Text = "Total de Registros: " & Me.GridView1.Rows.Count
Catch ex As Exception
Me.LabelInfo.Text = ex.Message
End Try
End Sub

Private Sub poblarListaAreasPadre()
Try

Me.DropDownList1.DataSource = ObjAreaMapper.SelectAreas
Me.DropDownList1.DataValueField = "IdArea"
Me.DropDownList1.DataTextField = "NombreArea"
Me.DropDownList1.DataBind()

Catch ex As Exception
Me.LabelInfo.Text = ex.Message
End Try
End Sub
End Class


Este es un diagrama que expone de manera general la arquitectura de la aplicación desarrollada






























Referencias
http://msdn2.microsoft.com/en-us/library/ms978496.aspx

http://builder.com.com/5100-6387-1049997.html



2 comentarios:

Anónimo dijo...

Hola Julio, soy Jose Antonio Contreras, desde que trabajamos en coemsa me comentaste de estos objetos, este ejemplo es muy ilustrativo, me ha servido mucho.

Con base a tu ejemplo estoy estructurando una aplicacion. Todo funciona perfecto, pero tengo una duda ... ¿Como extraigo un registro de la coleccion?. ya que la clase coleccion no tiene metodos para extraer.

Gracias y saludos.

Anónimo dijo...

It's enormous that you are getting thoughts from this article as well as from our dialogue made here.

My web blog; "Cheap Car Insurance England UK