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.








en
en
en
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.
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
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..
Hola, tengo una duda sobre el código, cuando se usan las transacciones? Por lo que veo no se usan nunca no?
Hola Javi, puedes usar estas sentencias:
Conexion.GDatos.IniciarTransaccion();
Conexion.GDatos.TerminarTransaccion();
Conexion.GDatos.AbortarTransaccion();
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.
En el ejemplo con Firebird descargable en la parte 5 del tutorial, se podría agregar este bloque para crear una transacción:
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..
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
Porque simplemente no utilizas getDate() del T-SQL? o existe una razon justificada para hacer lo que intentas?
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
Sigo sin comprender que quieres hacer con el UniversalTime. No sería mejor usar
Así con tu ejemplo:
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
Donde veo la implementacion de la capa de presentacion ??
Excelente articulo.
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
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