post icon

Como programar en n-Capas con C# (Parte 4)

En la cuarta entrega veremos una capa nueva, la capa de Negocios, como ya dije en los artículos anteriores hemos dado por terminado la capa de Acceso a Datos.

Aquí es donde diremos como debe procesarse la información. Para este caso no voy a crear una estructura compleja de BBDD ya que el código de C# ya lleva bastante, pero reflejará claramente como se usa ésta capa en casos más complejos.

Primeramente crearemos una tabla realmente simple, compuesta por 3 campos llamada Cliente.

1
2
3
4
5
6
7
8
9
CREATE TABLE [dbo].[Cliente](
	[IdCliente] [tinyint] NOT NULL,
	[DescripcionCliente] [varchar](50) NOT NULL,
	[Siglas] [varchar](15) NULL,
 CONSTRAINT [PK_Cliente] PRIMARY KEY CLUSTERED
(
	[IdCliente] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Preferentemente trabajaremos con procedimientos almacenados como Zeus manda. Para crear, listar y buscar tendremos 3 distintos procedimientos.

1
2
3
4
5
6
7
8
CREATE PROCEDURE [dbo].[insCliente]
	@id as int,
	@nombre varchar(50),
	@sigla varchar(15)
AS
BEGIN
	insert into Cliente values(@id, @nombre, @sigla);
END
1
2
3
4
5
CREATE PROCEDURE [dbo].[slcCliente]
AS
BEGIN
	select * from Cliente;
END
1
2
3
4
5
CREATE PROCEDURE [dbo].[slcCliente]
AS
BEGIN
	select * from Cliente;
END

Con esto ya tenemos creada la estructura de la base de datos completa, al menos hasta donde vamos a utilizar. Estos SP, se pueden considerar parte de la capa de negocios, no precisamente siempre tiene que estar en la aplicación, es lo que venía escribiendo en las primeras partes del tutorial.

Del lado de la aplicación utilizaremos el mapeo ORM (doy por sabido que conocen que esto, sino pueden investigarlo aquí), ya que es una de la prácticas más utilizadas y probadas que ahorran código y ayudan a cumplir con varios conceptos de la OOP. Dentro del mismo proyecto de biblioteca de clases, que estamos teniendo en nuestra solución (hasta ahora no hemos creado ningún tipo de interfaz de usuario). Creo conveniente crear una carpeta en la raíz del proyecto llamada Orm, justamente para seguir la convención (trato de seguirlas todas, derrepente se me escapa alguna, sabrán disculparme :S). Al crear esta carpeta, y crear clases dentro de ella también se creará un nuevo nivel de espacios de nombres: AccesoDatos.Orm.

A esta la llamaremos Cliente.cs, y así una clase por cada tabla que tengamos en nuestra BBDD. En ella crearemos 3 variables, que representarán los atributos de Cliente (mapeando los campos de la tabla). Al mismo tiempo de crear estos, crearemos sus setters y getters.

1
2
3
public short IdCliente { get; set; }
public string Descripcion { get; set; }
public string Sigla { get; set; }

Ahora es momento de utilizar el potencial del código que hemos venido escribiendo, veanlo en acción en los 3 métodos que crearemos, uno para dar de Alta, un registro de cliente, en la BBDD, otro para buscar, y otro para listar todos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{ Conexion.GDatos.Ejecutar("insCliente", cliente.IdCliente, cliente.Descripcion, cliente.Sigla, 3); }
 
public DataTable Listar()
{ return Conexion.GDatos.TraerDataTable("slcCliente"); }
 
public Cliente Listar(int idCliente)
{
	var cliente = new Cliente();
	DataTable dt = Conexion.GDatos.TraerDataTable("slcClienteById", idCliente);
 
	if (dt.Rows.Count > 0)
	{
		cliente.IdCliente = Convert.ToInt16(dt.Rows[0][0]);
		cliente.Descripcion = Convert.ToString(dt.Rows[0][1]);
		cliente.Sigla = Convert.ToString(dt.Rows[0][2]);
 
		return cliente;
	}
	return null;
}

En esta clase, deben crear todos los métodos, que correspondan a la clase cliente. Pueden crear todos los que quieran, sin importar que ésta clase quede muy larga, simplemente deben encargarse, que sea aquí donde corresponde una acción en sí. Como ven estamos aplicando sobrecarga de métodos en ésta clase (no lo confundan con polimorfismo).
La clase completa quedaría así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Data;
 
namespace AccesoDatos.Orm
{
    public class Cliente
    {
        // lista de atributos con setters y getters
        public short IdCliente { get; set; }
        public string Descripcion { get; set; }
        public string Sigla { get; set; }
 
        // métodos
        public void Crear(Cliente cliente)
        { Conexion.GDatos.Ejecutar("insCliente", cliente.IdCliente, cliente.Descripcion, cliente.Sigla, 3); }
 
        public DataTable Listar()
        { return Conexion.GDatos.TraerDataTable("slcCliente"); }
 
        public Cliente Listar(int idCliente)
        {
            var cliente = new Cliente();
            DataTable dt = Conexion.GDatos.TraerDataTable("slcClienteById", idCliente);
 
            if (dt.Rows.Count > 0)
            {
                cliente.IdCliente = Convert.ToInt16(dt.Rows[0][0]);
                cliente.Descripcion = Convert.ToString(dt.Rows[0][1]);
                cliente.Sigla = Convert.ToString(dt.Rows[0][2]);
 
                return cliente;
            }
            return null;
        }
    }
}

Con ésto vemos como se implementa la capa de negocios. En la siguiente entrega veremos ya la capa de Presentación, en lo posible, utilizares todas las clases hechas ya incluida ésta en una aplicación WinForm y otra WebForm, verán que no sólo es portable a cualquier proveedor de datos, sino que es portable a distintas plataformas de ejecución.

Parte 1 | Parte 2 | Parte 3 | Parte 5

Comentarios desde Facebook:

  1. avatar
    proser MEXICO Google Chrome Windows
    4 noviembre 2016 at 15:07 #

    SP para botón Buscar:

    USE [TEST]
    GO
    /****** Object: StoredProcedure [dbo].[slcClienteById] Script Date: 04/11/2016 11:37:25 a. m. ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER PROCEDURE [dbo].[slcClienteById]
    @id as int
    AS
    BEGIN
    select cliente.IdCliente as ID_Cliente,cliente.DescripcionCliente as Cliente,cliente.Siglas as Siglas from Cliente where cliente.IdCliente = @id;
    END

  2. avatar
    Martin Mendoza PERU Internet Explorer Windows
    24 agosto 2012 at 14:26 #

    Esta genial el articulo; pero como se haría para la creación de reportes?
    Gracias

  3. avatar
    Martin Mendoza PERU Internet Explorer Windows
    24 agosto 2012 at 11:45 #

    Como haces para trabajar con DataReader?

  4. avatar
    Javi SPAIN Mozilla Firefox Windows
    7 abril 2011 at 15:20 #

    Hola, tengo una pregunta sobre el código. Nunca se usan las transacciones?

    No estoy muy seguro pero creo que el valor de MTransaccion es null.

    Un saludo. Fantástico aporte.

  5. avatar
    Rodrigo Samtamaria COLOMBIA Internet Explorer Windows
    10 febrero 2011 at 11:46 #

    Buenos Dias, muchisimas gacias por su excelente aporte, nunca habia entendido bien el tema como hasta hoy, aprovecho para hacer una pregunta: en el ejemplo dicen que toca hacer una clase para cada tabla que tengamos, en mi caso yo tengo muchas tablas, pero muchas son por ejemplo 300 tablas, y en una consulta se referencian porlomenos 10 tablas, debo crear una clase para cada una de las 10 tablas que referencio en una consulta, o los datos que devuelven los procedimientos almacenados, porejemplo un select que trae registros de varias tablas, lo manejo como si fuera una sola tabla. Muchisimas Gracias

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      10 febrero 2011 at 19:15 #

      Si definitivamente si tienes 300 tablas, debes tener 300 clases. En el caso de unir varias tablas en un query debes elegir cual es la clase más importante en esa consulta y agregar el método en el y devolverlo como un Conjunto de Datos como por ejemplo un DataSet, DataTable, DataReader. No es necesario que crees por cada registro una instancia ni por cada tabla referenciada en el query. Tambien puedes optar por usar CollectionList de un objeto X pero no es recomendable con conjuntos de datos muy grandes..

      • avatar
        Javi SPAIN Mozilla Firefox Windows
        10 abril 2011 at 15:10 #

        Hola, tengo una duda sobre el código, cuando se usan las transacciones? Por lo que veo no se usan nunca no?

        • avatar
          GeekZero PARAGUAY Google Chrome Windows
          12 abril 2011 at 09:02 #

          Hola Javi, puedes usar estas sentencias:

          Conexion.GDatos.IniciarTransaccion();
          Conexion.GDatos.TerminarTransaccion();
          Conexion.GDatos.AbortarTransaccion();

        • avatar
          Javi SPAIN Mozilla Firefox Windows
          12 abril 2011 at 10:54 #

          Gracias por responder, GeekZero. Pero no tengo muy claro donde tengo que usar esos métodos. ¿Se supone que los tienes que llamar en la clase SqlServer o dónde exactamente?

          Podrías indicarme algún ejemplo??

          Gracias por todo.

        • avatar
          GeekZero PARAGUAY Google Chrome Windows
          13 mayo 2011 at 08:19 #

          En el ejemplo con Firebird descargable en la parte 5 del tutorial, se podría agregar este bloque para crear una transacción:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          
          public void Crear(Maestro[] maestro)
                  {
                      try
                      {
                          Conexion.GDatos.IniciarTransaccion();
           
                          Conexion.GDatos.Ejecutar("INS_MAESTRO", maestro[0].Id, maestro[0].Nombre, maestro[0].Apellido, maestro[0].FechaNacimiento);
                          Conexion.GDatos.Ejecutar("INS_MAESTRO", maestro[1].Id, maestro[1].Nombre, maestro[1].Apellido, maestro[1].FechaNacimiento);
           
                          Conexion.GDatos.ConfirmarTransaccion();
                      }
                      catch (Exception)
                      {
                          Conexion.GDatos.AbortarTransaccion();
                          throw;
                      } 
                  }
  6. avatar
    Oskar Kbrera COLOMBIA Internet Explorer Windows
    18 enero 2011 at 16:05 #

    Excelente articulo, me ha servido muchisimo, claro que emule a visual basic .net, ya que en esta heramineta trabajo. Me imagino que la implementacion de actualizacion y eliminacion de registros es igual a la de crear, solo se debe tener en cuenta en eliminar la integridad referencial(para no borrar un registro padre que tenga hijos).

    Excelente amigo..

  7. avatar
    juansalazar COLOMBIA Google Chrome Windows
    17 noviembre 2010 at 12:53 #

    Buen dia

    Me ha sido de gran utilidad el articulo, pero tengo un porblema. Necesito enviar la fecha actual la saco de esta manera

    DateTime created_at = DateTime.Today;
    DateTime _created_at = created_at.ToUniversalTime();

    y lo mando como parametro
    public void Crear(Cliente cliente)
    { Conexion.GDatos.Ejecutar(“insCliente”, cliente.date_at, ); } cuando le doy crear me aparece el siguiente error “Failed to convert parameter value from a String to a DateTime.” la fecha esta tal cual como aparece en sql server. Si me pueden colaborar. En la base de datos esta como datetime y en el procedimiento tambien

    Espero su colaboración muchas gracias

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      17 noviembre 2010 at 14:49 #

      Porque simplemente no utilizas getDate() del T-SQL? o existe una razon justificada para hacer lo que intentas?

      • avatar
        juansalazar COLOMBIA Google Chrome Windows
        17 noviembre 2010 at 16:38 #

        GeekZero muchas gracias por contestar

        el metodo completo es asi
        public void Crear(Cliente cliente)
        {
        DateTime created_at = DateTime.Today.ToUniversalTime();
        //DateTime _created_at = created_at.ToUniversalTime();
        //_created_at = _created_at.Substring(0, _created_at.Length – 5);
        //DateTime.Today.ToString(“MM/dd/yy”)
        Conexion.GDatos.Ejecutar(“isnUsers”, cliente.Id_user, cliente.name, cliente.last_name, cliente.address, cliente.state, cliente.city, cliente.country, cliente.postal_code, cliente.phone_number, cliente.email, cliente.password, cliente.profile_idprofile, created_at);
        }

        en la base de datos

        insert into users values(@id, @nombre, @apellido, @address, @state, @city, @country, @postal_code, @phone, @email, @password, @profile, @date_at);

        lo trate de hacer como me comentas pero entonces me dice que falta un parámetro en la función Conexion.GDatos.Ejecutar el de la fecha porque no enivaria la fecha. o no se hay otra forma de hacerlo

        muchas gracias

        • avatar
          GeekZero PARAGUAY Google Chrome Windows
          17 noviembre 2010 at 17:50 #

          Sigo sin comprender que quieres hacer con el UniversalTime. No sería mejor usar

          1
          
          DateTime.Now;

          Así con tu ejemplo:

          1
          
          Conexion.GDatos.Ejecutar(“isnUsers”, cliente.Id_user, cliente.name, cliente.last_name, cliente.address, cliente.state, cliente.city, cliente.country, cliente.postal_code, cliente.phone_number, cliente.email, cliente.password, cliente.profile_idprofile, DateTime.Now);
        • avatar
          juansalazar COLOMBIA Google Chrome Windows
          17 noviembre 2010 at 18:43 #

          Muchas gracias. El error lo estaba cometiendo en los parámetros del procedimiento de bases de datos. la fecha en un lugar diferente, que como lo mandaba. igual utilice el que me recomendó (DateTime.Now) y funciona excelente. Muchas gracias por su ayuda

  8. avatar
    Jose Mendoza UNITED STATES Mozilla Firefox Windows
    2 agosto 2010 at 19:22 #

    Donde veo la implementacion de la capa de presentacion ??

    Excelente articulo.

    • avatar
      GeekZero PARAGUAY Google Chrome Windows
      2 agosto 2010 at 19:50 #

      Hola Jose,

      La capa de presentacion esta en la parte 5, aqui lo tienes:

      http://www.devtroce.com/2010/07/14/como-programar

      Espero te sirva

      • avatar
        Andres HG MEXICO Mozilla Firefox Windows
        2 julio 2011 at 23:12 #

        Buenas Noches,

        Antes que nada muchas gracias por este tutorial me ha servido de mucho para entender esto de las capas.

        Nada mas creo que falto el SP slcClienteById ya que en el post el slcCliente esta repetido.

        Saludos desde monterrey, NL. Mx

Trackbacks/Pingbacks

  1. Programacion en 3 Capas con C# - SQL Server | DevTroce.com UNITED STATES WordPress - 22 mayo 2012

    […] 1 |Parte 3 | Parte 4 | Parte […]

  2. Como programar en n-Capas con C# (Parte 3) | DevTroce.com WordPress - 15 agosto 2010

    […] 1 | Parte 2 | Parte 4 | Parte […]

  3. Tweets that mention Programación en 3 Capas con C# - Parte 4 | DevTroce.com -- Topsy.com UNITED STATES - 13 julio 2010

    […] This post was mentioned on Twitter by Ronald Riveros. Ronald Riveros said: RT @devtroce: Como programar en n-Capas con C# (Parte 4): En la cuarta entrega veremos una capa nueva, la… http://goo.gl/fb/fe4Mt […]

Responder