abril 17, 2007

Ejemplo de Aplicación ASP.NET 2.0 en capas con DataSet Tipado

Para el desarrollo de esta aplicación utilizamos Visual Basic .NET con Visual Studio .NET 2005.

Estrucutura del proyecto ASP.NET
- Una carpeta App_Code con:

  • Una clase Area. Que hace uso de los métodos de la Clase del tipo Business Entities representada por un TableAdapter de un DataSet.

  • Una clase DataSet. Contiene un DataSet tipado el cual contiene los TableAdapter que representan a cada uno de los objetos Entitie con sus respectivos métodos de Acceso a Datos.


- 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 el DataSet Tipado y para cada objeto entidad existe un TableAdapter con los métodos necesarios para el Acceso a Datos. Y la clase Area que representa como una clase Control que se comunica con las clases Entity y sus metodos de acceso a datos para luego hacer DataBinding con controles en la GUI.

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 la tabla de la base de datos correspondiente al Area y los datos que regresa el store procedure que estaremos ejecutando.



Implementación del DataSet que contiene a los TableAdapters que representan a nuestros objetos Business Entities.

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

Para nuestro ejemplo utiizaremos el caso de DataSet Tipados. En la siguiente imagen podemos observar como se representa nuestro Business Entiy Area y en la parte baja observamos los métodos de acceso a datos que nos permiten poblar al Businness Entity representado como un DataTable.




Implementación del Objeto Area.

Este objeto es como un objeto control que invoca a los métodos de acceso a datos definidos para cada TableAdapter

Imports Microsoft.VisualBasic

Public Class Area

Public Function ObtenerAreas() As DataSet1.AREADataTable
Dim AreasAdapter As New DataSet1TableAdapters.AREATableAdapter()
Dim Areas As DataSet1.AREADataTable = AreasAdapter.GetData
Return Areas
End Function

End Class

Podemos observar que esta clase crea una instacia del adaptador correspondiente al objeto Entity que deseamos trabajar en este caso: “AreaTableAdapter” luego invocamos su método de acceso a datos llamado GetData que nos regresa un DataTable con cada una de las áreas y que retornamos a la capa GUI para hacer DataBinding con un GridView.

Implementación de la capa de Presentación GUI

En esta capa es en donde vamos a poblar los controles visuales. El GridView se carga durante el evento Load de la página aquí crea una instancia del objeto Control Area y éste expone un método público que obtiene las Area que nos regresa en un objeto DataTable con el cual hacemos DataBinding al GridView.


Partial Class Default2
Inherits System.Web.UI.Page

Dim objArea As New Area

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then

Dim objArea As New Area
Me.GridView1.DataSource = objArea.ObtenerAreas
Me.GridView1.DataBind()

End If
End Sub

'Implementación del Pagineo la Grid
Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging
Me.GridView1.PageIndex = e.NewPageIndex
Me.GridView1.DataSource = objArea.ObtenerAreas()
Me.GridView1.DataBind()
End Sub

'Borrar el registro seleccionado en el Grid
Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting
'Para detectar el segundo postback generado por el ButtonField del tipo Image se verifican sus coordenadas x y.
If (Me.Request("x") Is Nothing) AndAlso (Me.Request("y") Is Nothing) Then

Dim iAffect As Int16
objArea = New Area
iAffect = objArea.DeleteArea(Me.GridView1.Rows(e.RowIndex).Cells.Item(0).Text)
Else
Me.GridView1.DataSource = objArea.ObtenerAreas()
Me.GridView1.DataBind()
End If
End Sub

'Al seleccionar un área se muestra en los controles independientes.
Protected Sub GridView1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles GridView1.SelectedIndexChanged
Me.LabelIdArea.Text = Me.GridView1.Rows(Me.GridView1.SelectedIndex).Cells.Item(0).Text
Me.TextBox2.Text = Me.GridView1.Rows(Me.GridView1.SelectedIndex).Cells.Item(1).Text
Me.TextBox1.Text = Me.GridView1.Rows(Me.GridView1.SelectedIndex).Cells.Item(2).Text
Me.CheckBox1.Text = Me.GridView1.Rows(Me.GridView1.SelectedIndex).Cells.Item(3).Text
End Sub


End Class

Conclusión: Ésta es una de las formas propuestas por Microsoft.

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



Excelente artículo DateSet vs. Colecciones de Objetos

Este es el link a un excelente articulo que expresa ventajas y desventajas de usar DataSets y Colecciones de Objetos, cuando usar unos y otros. Muchas veces como desarrolladores utilizamos lo que nos dicen los manuales de microsoft o los libros, pero no sabemos tecnicamente que es mejor, tomamos lo que mejor entendemos o lo que nos parece más fácil, pero creo que esto no es del todo correcto.

http://msdn.microsoft.com/msdnmag/issues/05/08/CuttingEdge/

Algo de lo que dice este articulo con respecto a los DataSets es que estos implementan la serialización de manera automática, pero ésta tiene un costo muy considerable cuando se hace para miles de registros. Soportan la concurrencia optimista, el databinding , permiten la implementación de links lógicos entre tablas cuyo fin es hacer árboles hijos de datos, pero esto último comunmente no es utilizado.

Con respecto a las colecciones de objetos cuya implementación requiere heredar de la clase
CollectionBase son considerablemente más rápidos en la recuperación de datos entre las capas. Requieren un mayor trabajo de codificación.

En conclusión el artículo propone pensar muy bien en usar DataSet ya que al parecer estos presentan más desventajas , claro esto depende de la funcionalidad que se requiera ya que los DataSet soportan funcionalidad que no soportan las colecciones de objetos aunque estos últimos presentan un mayor desempeño.

marzo 22, 2007

Utiles NET 2.0

Crear y acceder a los métodos de un TableAdapter definido en un DataSet tipado.

'Esta función retorna una DataTable después de crear el TableAdapter y ejecutar el método definido en la mismo.
Public Function ObtenerAreasXEsActiva() As DataSet1.AREADataTable
Dim AreasAdapter As New DataSet1TableAdapters.AREATableAdapter()
Dim Areas As DataSet1.AREADataTable
Areas = AreasAdapter.GetDataByEsActivaArea(1)
Return Areas
End Function

----------------------------------------------------------------

Recuperar de web.config

Forma 1:My.Settings.Item("ConnectionStringCaja")
Forma 2:My.Settings.strSQLServer

-----------------------------------------------------------
Accesar a una celda de un GridView
DataGridView1.Rows(0).Cells(0).Value = DateTime.Now 'Colocar el valor.
DataGridView1.Rows(0).Cells(0).Style.Format = "d"
MessageBox.Show(DataGridView1.Rows(0).Cells(2).Value)

Recuperar el valor de la celda seleccionada en el GridView por ejemplo al evento
SelectedIndexChanged.


sValor = Me.GridView1.Rows(Me.GridView1.SelectedIndex).Cells.Item(0).Text

------------------------------------------------------------

Condición necesaria para manejar el doble postback de un
ButtonField del tipo image en un GridView. Por ejemplo al evento RowDeleting

Protected Sub GridView1_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles GridView1.RowDeleting

If (Me.Request("x") Is Nothing) AndAlso (Me.Request("y") Is Nothing) Then
objArea = New AreaBLL
objArea.DeleteArea(Me.GridView1.Rows(e.RowIndex).Cells.Item(0).Text)
Else
Me.GridView1.DataSource = objArea.ObtenerAreas()
Me.GridView1.DataBind()
End If
End Sub

--------------------------------------------------------------------------------------------

Implementar el pagineo en el GridView


Protected Sub GridView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewPageEventArgs) Handles GridView1.PageIndexChanging

'Asignar el nuevo índice d página solicitado.
Me.GridView1.PageIndex = e.NewPageIndex
Me.GridView1.DataSource = objArea.ObtenerAreas()
Me.GridView1.DataBind()


End Sub

Utiles SQL Server

Registros que están en A, pero no en B

SELECT NombreEmp FROM EMPLEADO WHERE (IdEmpleado NOT IN (SELECT IdEmpleado FROM EMPLEADO_AREA))

---------------------------------------------------------------------------------------

Obtener registros duplicados

select au_lname count(*) from dup_authors group by au_lname having count(*) > 1

----------------------------------------------------------------------------------------

Consulta con apostrofe

Select ApPat From EmpleadoWhere ApPat = 'O''Rally'

-----------------------------------------------------------------------------------------

Obtener sólo la fecha de un DateTime

SELECT CONVERT(CHAR(10), FechaAltaCustodia, 103) AS SoloFecha FROM FOLIO_CUSTODIA
------------------------------------------------------------------------------------------
Convert con redondeo

Select Convert(numeric(3,0), 987.654)--Salida 988

------------------------------------------------------------------------------------------
Case

SELECT Nombre,
EsActivo= CASE
WHEN EsActivo= 0 THEN 'No'
WHEN EsActivo= 1 THEN 'Si'
END
FROM Tabla1

------------------------------------------------------------------------------------------
Uso de Exist

IF EXISTS(SELECT * FROM authors WHERE au_fname = 'Elmer')
PRINT "Existen los datos"
ELSE

RAISERROR('No existen los datos')

------------------------------------------------------------------------------------------

Utiles VB.NET 1.1

VB NET ASP 1.1
Recuperar el valor de una celda de un DataGrid

En el evento
DataGrid1.SelectedIndexChanged


Session("Id") = Me.DataGrid1.SelectedItem.Cells(0).Text


--------------------------------------------------------------------------------------------
VB NET ASP 1.1
Recuperar el total de renglones en un DataGrid

Session("TotalRenglones") = Me.DataGridMetricasMeta.Items.Count()

--------------------------------------------------------------------------------------------
VB NET ASP 1.1
Obtener el texto del item seleccionado, ya que el dropdownlist no cuenta con una propiedad text directamente.

Me.DropDownListProducto.Items(Me.DropDownListProducto.SelectedIndex).Text

--------------------------------------------------------------------------------------------
VB NET ASP 1.1

Recuperar el valor de archivo web.config

'Extraer la cadena de conexión del archivo web.config en una variable de aplicación.
Application("ServerBD") = ConfigurationSettings.AppSettings("ServerBD")

--------------------------------------------------------------------------------------------
VB NET ASP 1.1
Poner texto en un dropdownlist como si se tratará de una caja de texto.

Me.DropDownList1.SelectedItem.Text = "Seleccione un valor"

--------------------------------------------------------------------------------------------
VB NET ASP 1.1
Ocultar columna del DataGrid

Me.DataGridMetricasMeta.Columns(6).Visible = False

--------------------------------------------------------------------------------------------
VB NET ASP 1.1
Encontrar y seleccionar un item basado en un texto en un DropDownList


DropDownList1.SelectedValue = DropDownList1.Items.FindByText("Ilumina").Value

------------------------------------------------------------------------------------------

Validar existencia de nulo en el resultado de un DataReader

If IsDBNull(dr("ObsDocto")) then

End if

------------------------------------------------------------------------------------------

Pasar parametros a un comando

cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID

cmd.Parameters.Add("@Name", SqlDbType.Int).Value = System.DBNull.Value--Valor nulo

------------------------------------------------------------------------------------------

Ejecutar una Transacción ADO.NET

cn.Open

Dim trans as SqlTrasaction = cn.BeginTransaction
Dim cmDel as New SqlCommand()

cmDel.Connection = cn

cmDel.Transaction = trans


Try

cmDel.CommandText = "Delete TablaDetalle Where Product = 12"

cmDel.ExecuteNonQuery()


cmDel.CommandText = "Delete TablaEnc Where Product = 12"

cmDel.ExecuteNonQuery()


trans.Commit()

Catch Ex as Exception

trans.Rollback()

Finally

cn.Close()

End try

febrero 18, 2007

Tipo Nullable

Por ejemplo el tipo entero (Integer en VB) no tenia forma de tener un valor nulo. Esto permite guardar valores nulos en la base de datos.

'Declarar la variable
Dim nul as Nullable(Of Integer)

'Verificar el valor
If nul.HasValue Then
'Tiene valor
End if

enero 08, 2007

Utilizar el Patron Singleton con formularios MDI

Objetivo: Que desde una aplicación Windows sólo podamos tener una forma hija abierta.

-------1. En la forma hija

'Variable global
Private Shared frmInstance As frmReport = Nothing

'Finalmente crearemos una función shared que será la que finalmente controlara la creación o manejo de la instancia del formulario, logrando obtener solo un formulario 'abierto para este form1.


'Función que verifica sola a una instancia del form1
Public Shared Function Instance() As form1
If frmInstance Is Nothing OrElse frmInstance.IsDisposed = True Then
frmInstance = New form1
End If
frmInstance.BringToFront()
Return frmInstance
End Function

'2-En la forma padre.
'Ahora en el padre escribiremos el llamado al hijo para crear la instancia, o si ya esta 'creada, entonces pondrá el formulario hijo en frente para que lo podamos ver.

Dim frmHijo as form1 = form1.Instance
frmHijo.MdiParent = Me
frmHijo.Show

Referencia:
href="http://www.mentores.net/articulos/Percynet_EditorTexto.htm"

El Patrón Singleton

Objetivo: Hacer que la instancia de un objeto sea accesible globalmente, y que sea única. Para ello es necesario crear un método en la clase que se desee sólo tener una instancia a la ves.

Yo por ejemplo hice un objeto mapper el cuál necesitaba que no fuera instanciado más de una vez por la aplicacion que lo usara.

'---1 La clase Singleton-----------------------------------------------------
Public Class MapperEmpleado
Private pnombre As String

Public Property nombre() As String
Get
Return pnombre
End Get
Set(ByVal Value As String)
pnombre = Value
End Set
End Property

Private Shared mInstance As MapperEmpleado
Private Shared mMutex As New System.Threading.Mutex()

' Constructor privado para no poder instanciar la clase
Private Sub New()
End Sub

'Método que verifica la existencia del objeto al querer instanciar.
Public Shared Function GetInstance() As MapperEmpleado
mMutex.WaitOne()
If mInstance Is Nothing Then
mInstance = New MapperEmpleado()
End If
mMutex.ReleaseMutex()
Return mInstance
End Function

End Class

--2 La aplicación desde que se consume a la clase que implementa el patrón singleton.

'Para poder instanciar el objeto se usa el método GetInstance ya que el constructor New() es privado.
Dim obj As MapperEmpleado = MapperEmpleado.GetInstance
obj.nombre = "Julio"
Dim obj2 As MapperEmpleado = MapperEmpleado.GetInstance
MessageBox.Show(obj2.nombre)
--El nombre es el mismo porque sólo se permite una clase.


Aquí un link de referencia sobre este patrón:
http://www.mug.org.ar/Patrones/ArticPatrones/304.aspx

http://searchvb.techtarget.com/tip/0,289483,sid8_gci921128,00.html

diciembre 11, 2006

Check box en GridView para procesar renglones seleccionados

Recientemente tuve la necesidad de poner un ccheck box en cada una de las filas de un control GridView para que poder seleccionar a un número determinado de ellas y asi poder procesarlas.




1. Agregar el control check box al GridView como parte de sus columnas:



2. Recorrer a todos los renglones del GridView para identificar cuales están seleccionados.

'Obtener el total de renglones para saber cunado parar durante la iteración.
Dim intRows As Int16 = Me.GridViewEdoCta.Rows.Count

For i = 0 To Me.GridViewEdoCta.Rows.Count - 1
'En la posición 13 es en donde se encuentra el control Check.
If CType(Me.GridViewEdoCta.Rows(i).Cells(13).Controls(1), CheckBox).Checked Then
CargoxContrato = Me.GridViewEdoCta.Rows(i).Cells(0).Text
End If
Next

Inserciones, Actulizaciones y Borrados masivo de registros

En el siguiente ejemplo se expone como hacer Deletes y Updates masivamente con el uso de XML, sólo es necesario pasar el árbol XML al store procedure para leerlo y especificarlo en las intrucciones delete y update. La´página web referencia es:

http://support.microsoft.com/kb/316244/es

Cadena xml válida que recibe el sp:


CREATE PROCEDURE sps_CancelaCargosXContratoTelXML
@xmlCargosxContrato varchar(8000) AS

DECLARE @idoc int --xmlDoc

--Ejecutar el sp que carga en memoria el docuemnto XML.
EXEC sp_xml_preparedocument @idoc output, @xmlCargosxContrato

--Comienza la transacción
BEGIN TRANSACTION
--Actualizar el Status de los cargos a Cancelado.

UPDATE Tel_CargosxContrato SET Tel_CargosxContrato.Status = 'CANCELADO'FROM OPENXML (@idoc, '/CargosxContrato/Concepto')
WITH (CargoUid varchar(11)) Tel_CargosxContratoXML
WHERE Tel_CargosxContrato.Uid = Tel_CargosxContratoXML.CargoUid

--Verificar si hubo errores saltar al bloque manejador.

IF @@Error != 0
GOTO ERROR_HANDLER
--Eliminar cargos de la tabla TEL_Cobranza

Delete Tel_cobranza
FROM OPENXML (@idoc, '/CargosxContrato/Concepto')
WITH (CargoUid varchar(11)) CobranzaXMLWHERE Tel_Cobranza.Uid = CobranzaXML.CargoUid

--Verificar si hubo errores saltar al bloque manejador.
IF @@Error != 0
BEGIN
GOTO ERROR_HANDLE

--Finalizar la Transacción pues todo salió bien.
COMMIT TRANSACTION
SET NOCOUNT OFF
--Descargar documento XML de la memoria.
EXEC sp_xml_removedocument @idoc
RETURN 0

--Manejador de Error.
ERROR_HANDLER:
ROLLBACK TRANSACTION--Descargar documento XML de la memoria.EXEC sp_xml_removedocument @idoc
SET NOCOUNT OFF
RETURN 0
GO

Ocultar columnas con DataBind en un GridView

Es muy comun el poblar un control GridView con datos de una Base de Datos y ocultar columnas que no es recomendable que se muestran a los usuarios, pero en el GridView al poner la propiedad visible= False de una columna a ocultar y luego tratar de recuperar el valor de esta celda el valor es cadena vacía, para que esto no courra se debe implementar el siguiente evento manejado del GridView y aquí poner las columnas que se desea ocultar.

'Ocultar columnas del GridView que no son necesarias para el usuario en la vista.
Public Sub myGrid_OnRowCreated(ByVal sender As Object, ByVal e As Web.UI.WebControls.GridViewRowEventArgs) Handles GridViewEdoCta.RowCreated
e.Row.Cells(0).Visible = False 'Uid cobranza
e.Row.Cells(1).Visible = False 'MovimientoUid
End Sub

De esta forma si es posible recuperar su valor.
'Recuperar el valor de la celda, aunque este oculta.
Dim strClave as String = Me.GridViewEdoCta.Rows(1).Cells(0).Text

Imprimir directamente con ASP.NET


1. En el evento Load cargo la lista de impresoras disponibles localemente.

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Me.DropDownListImpresoras.DataSource = PrinterSettings.InstalledPrinters()
Me.DropDownListImpresoras.DataBind()
Me.DropDownListImpresoras.SelectedIndex = 0
End If
End Sub

2. Al hacer clic en el botón imprimir
Protected Sub ButtonImprimir_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonImprimir.Click
'Create an instance of PrintDocument
Dim printdoc As New System.Drawing.Printing.PrintDocument()
' Set the printer name
printdoc.PrinterSettings.PrinterName = Me.DropDownListImpresoras.Text
' Handle printing
AddHandler printdoc.PrintPage, AddressOf Me.printdoc_PrintPage
' Print!
printdoc.Print()
End Sub

3. Evento manejado al imprimir que es en donde se especifica lo que se desea imprimir.

Private Sub printdoc_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
'Definición de la fte a utilizar.
Dim printFont As System.Drawing.Font = New System.Drawing.Font("Courier New", 12)

' Dibujar el nombre escrito y que se desea imprimir directamente.
e.Graphics.DrawString(Me.TextBox1.Text, printFont, System.Drawing.Brushes.Black, New System.Drawing.PointF(10.0F, 50.0F))
End Sub

noviembre 08, 2006

Script para Activar/Desactivar Constraints en SQL Server

Muchas veces es necesario deshabilitar la integridad referencial o ciertos constraints establecidos en una base de datos SQL Server y este script que encontré en "http://www.melkorcete.com/index.php?c=17" es muy útil para llevar acabo esta tarea.


/*
Script para Activar y Desactivar todos los constraints de una
Base de Datos (CK, FK, PK, DK).

Sólo se especiifca 1 para activar o 0 para desactivar a la variable @p_activar
*/

USE Facturacion

DECLARE @p_activar BIT
SET @p_activar = 1 --Para Activar = 1, Desactivar = 0

Declare @v_retorno int

Begin
Set NoCount Off

-- Almacena la Orden
declare @orden varchar(100)
-- Almacena la Tabla
declare @tabla varchar(100)
-- Almacena el numero de Operacion Realizada
declare @contador int
-- Variables para mensaje
declare @no varchar(2)
declare @des varchar(4)

-- Para la construccion de mensajes se da un valor
-- dependiendo del parametro @p_activar
if @p_activar = 1
begin
set @no = null
set @des = 'A'
end
else
begin
set @no = 'NO'
set @des = 'Desa'
end

-- Cursor para recorrer una a una las Constraints
declare CURSORITO cursor for
SELECT 'ALTER TABLE ' + QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) + ' ' + IsNull(@no,'') + 'CHECK CONSTRAINT ALL',TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE
OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)), 'IsMSShipped') = 0
AND TABLE_TYPE = 'BASE TABLE'

-- Inicializacion de Variables
set @orden = ''
set @tabla = ''
set @contador = 0

-- Mensaje de entrada
print ' '
print '####################################################'

if @no = 'NO'
print '### DESACTIVADO DE CONSTRAINTS ###'
else
print '### ACTIVADO DE CONSTRAINTS ###'

print '####################################################'
print '### '

-- Iniciamos el Cursor y lo recorremos
OPEN CURSORITO
fetch next from CURSORITO
into @orden,@tabla
while @@fetch_status = 0
begin
-- Contador ++
set @contador = @contador + 1
-- Ejecutamos la Orden
exec(@orden)
-- Crear mensaje de salida
print '### ' + convert(varchar,@contador) + ' - ' + convert(varchar,@des) + 'ctivado de ' + convert(varchar,@tabla) + ' completado.'
-- Siguiente Vuelta
fetch next from CURSORITO into @orden, @tabla
end
-- cerramos el cursor
close CURSORITO
deallocate CURSORITO

-- Mensaje de Fin
print '### '
print '####################################################'

if @@error = 0
print '### FINALIZADO CORRECTAMENTE ###'
else
print '### FINALIZADO CON ERRORES ###'

print '####################################################'

Select @v_retorno = @@error
End

octubre 16, 2006

Un control Web ASP. net que expone un dialogo de espera

Este en un control asp net que funciona para la versión 1.1 y 2 y que es muy útil para mostrar al usuario cuando éste debe esperar a que se procese la página.

El link es:


http://busyboxdotnet.qsh.eu/



Revisen el demo. Considero que es un control free muy útil.

octubre 13, 2006

Encriptado de información del ViewState ASP 2.0

Para reducir el riesgo que alguien intercepte la información almacenada en el ViewState, es posible cifrar dicha información.

Los valores aceptados de la propiedad ViewStateEncryptionMode son:

Always: La información del ViewState siempre es encriptada. Si la aplicación maneja información sensible de manera constante seria conveniente utilizar este valor.

Auto: La información es encriptada si un control lo solicita. Este es el valor por defecto de la propiedad.

Never: La información nunca es encriptada, aún si un control lo solicita. Úselo bajo su propia responsabilidad...

Para establecer el valor a nivel de aplicación empleamos el atributo ViewStateEncryptionMode de la sección pages en el web.config:

pages viewStateEncryptionMode="Always"


O bien por medio del atributo homónimo de la directiva @Page, para establecer el valor en una página en particular:

@Page ViewStateEncryptionMode="Always"

También se puede establecer el valor de manera dinámica a través de la propiedad ViewStateEncryptionMode del objeto Page:

Page.ViewStateEncryptionMode = ViewStateEncryptionMode.Auto

Así pues, utilizando el valor por defecto (Auto) de la propiedad ViewStateEncryptionMode, si se requiere que la información del ViewState sea encriptada, se debe llamar al método RegisterRequiresViewStateEncryption del objeto Page:

If () Then
Page.RegisterRequiresViewStateEncryption()
End If

Formatear (Identación) las instrucciones SQL

Navegando por Internet encontré este formateador de instrucciones SQL en línea, me gusto mucho pues resulta muy útil para cuando hacemos scripts, stores procedures o disparadores.


Este es el link de referencia:

http://www.wangz.net/cgi-bin/pp/gsqlparser/sqlpp/sqlformat.tpl

octubre 05, 2006

EXISTS vs. COUNT(*) en SQL Server

Es muy común que querramos saber la existencia de datos en determinada tabla de una base de datos y para ello utilizamos EXISTS o COUNT(*), pero qué es más eficiente?

Pues en un artículo que muestra como es más eficiente utilizar EXISTS.


IF EXISTS(SELECT * FROM OrderDetails
WHERE orderid = 10248)
PRINT 'yes'
ELSE
PRINT 'no'

Este es el link de referencia:

http://www.sqlmag.com/Article/ArticleID/38039/sql_server_38039.html