Con ésta entrega cumpliremos con la capa de Presentación, utilizaremos todo lo que hemos visto hasta ahora aplicados a una interfaz de usuario, y como lo prometí, lo veremos implementado en winForm como en webForm.
El primer ejemplo será Desktop, crearemos un formulario con una apariencia semejante al que ven en la imagen.
Evidentemente, un sistema real no lo harán así, el botón conectar emula el comportamiento de una pantalla de login, el boton crear mandará a la BBDD los datos de la caja, Listar rellenará la grilla y Buscar By Id se encargará de devolvernos un registro a partir de lo que carguemos en la caja de Id. Otra implementación interesante sería agregarle un identity a la tabla cliente, pero para el ejemplo ya servirá esto. Para esto crearemos 2 proyectos más dentro de nuestra solución, uno será una aplicación Windows Form con Visual C#, y la otra un sitio Web.
El código que pondremos en el botón conectar es como sigue, recuerden que es conveniente armarlo dinamicamente con una pantalla de login especialmente el usuario y el pass. Con esto logramos armar toda la capa de Acceso a Datos, no se mantiene conectada la aplicación, sino solo sus valores de conexión en memoria.
1 2 3 4 5 6 7 8 9 | try { Conexion.IniciarSesion("127.0.0.1", "Queryable", "sa", "123"); MessageBox.Show(String.Format("{0}", "Se conecto exitosamente")); } catch (Exception ex) { MessageBox.Show(ex.Message); } |
Para crear un nuevo cliente instanciamos un objeto cliente del tipo Cliente, le seteamos sus atributos, a partir de los valores de la caja de texto, e invocamos el método crear enviandole el nuevo objeto cliente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var cliente = new Cliente(); try { cliente.IdCliente = Convert.ToInt16(txtIdCliente.Text); cliente.Descripcion = txtDescripcionCliente.Text; cliente.Sigla = txtSiglaCliente.Text; cliente.Crear(cliente); MessageBox.Show(String.Format("{0}", "Se creo exitosamente")); } catch (Exception ex) { MessageBox.Show(ex.Message); } |
Luego de esto escribimos el código de listado de todos los clientes, y lo cargamos en la grilla. Se dan cuenta que necesitamos muy pocas lineas de código en la capa de Presentación, y que no tiene una dependencia de la BBDD?. Si se dan cuenta, cuando vamos a devolver muchos registros no podemos utilizar un montón de instancias de Cliente, sino simplemente devolvemos un DataTable, DataSet o DataReader.
1 2 3 4 5 6 7 8 9 | var cliente = new Cliente(); try { grilla.DataSource = cliente.Listar(); } catch (Exception ex) { MessageBox.Show(ex.Message); } |
Finalmente el código de búsqueda quedaría algo asi. Cómo sabemos que si buscamos por la PK, siempre nos devolverá un sólo registro, lo podemos crear como un objeto Cliente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var cliente = new Cliente(); try { cliente = cliente.Listar(Convert.ToInt16(txtIdCliente.Text)); if (cliente != null) { txtDescripcionCliente.Text = cliente.Descripcion; txtSiglaCliente.Text = cliente.Sigla; } else { MessageBox.Show(String.Format("{0}", "No existia el cliente buscado")); } } catch (Exception ex) { MessageBox.Show(ex.Message); } |
El código completo 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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | using System; using System.Windows.Forms; using AccesoDatos; using AccesoDatos.Orm; namespace Test { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnConectar_Click(object sender, EventArgs e) { try { Conexion.IniciarSesion("127.0.0.1", "Queryable", "sa", "***"); MessageBox.Show(String.Format("{0}", "Se conecto exitosamente")); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnListar_Click(object sender, EventArgs e) { var cliente = new Cliente(); try { grilla.DataSource = cliente.Listar(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnCrear_Click(object sender, EventArgs e) { var cliente = new Cliente(); try { cliente.IdCliente = Convert.ToInt16(txtIdCliente.Text); cliente.Descripcion = txtDescripcionCliente.Text; cliente.Sigla = txtSiglaCliente.Text; cliente.Crear(cliente); MessageBox.Show(String.Format("{0}", "Se creo exitosamente")); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void btnBuscarById_Click(object sender, EventArgs e) { var cliente = new Cliente(); try { cliente = cliente.Listar(Convert.ToInt16(txtIdCliente.Text)); if (cliente != null) { txtDescripcionCliente.Text = cliente.Descripcion; txtSiglaCliente.Text = cliente.Sigla; } else { MessageBox.Show(String.Format("{0}", "No existia el cliente buscado")); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } |
Con respecto a la parte web, tendremos 2 partes, el código ASP.net, y el c#, veamoslo, se los dejo completamente de una:
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Cliente.aspx.cs" Inherits="Cliente" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> </head> <body> <form id="frmCliente" runat="server"> <div> <asp:Label ID="Id" runat="server" Text="Id: "></asp:Label> <asp:TextBox ID="txtIdCliente" runat="server"></asp:TextBox> <br /> <asp:Label ID="Label1" runat="server" Text="Descripcion: "></asp:Label> <asp:TextBox ID="txtDescripcionCliente" runat="server"></asp:TextBox> <asp:TextBox ID="txtuser" runat="server">sa</asp:TextBox> <br /> <asp:Label ID="Label2" runat="server" Text="Siglas: "></asp:Label> <asp:TextBox ID="txtSiglasCliente" runat="server"></asp:TextBox> <br /> <hr style="margin-top: 0px; margin-bottom: 0px" /> <asp:GridView ID="grilla" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None"> <AlternatingRowStyle BackColor="White" /> <EditRowStyle BackColor="#2461BF" /> <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" /> <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" /> <RowStyle BackColor="#EFF3FB" /> <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" /> <SortedAscendingCellStyle BackColor="#F5F7FB" /> <SortedAscendingHeaderStyle BackColor="#6D95E1" /> <SortedDescendingCellStyle BackColor="#E9EBEF" /> <SortedDescendingHeaderStyle BackColor="#4870BE" /> </asp:GridView> <asp:Label ID="Label3" runat="server" Text="Estado:"></asp:Label> <asp:Label ID="lblEstado" runat="server"></asp:Label> <br /> <asp:Button ID="btnConectar" runat="server" Text="Conectar" onclick="btnConectar_Click" /> <asp:Button ID="btnCrear" runat="server" onclick="btnCrear_Click" Text="Crear" /> <asp:Button ID="btnListar" runat="server" onclick="btnListar_Click" Text="Listar" /> <asp:Button ID="btnListarById" runat="server" onclick="btnListarById_Click" Text="Listar By Id" /> <br /> </div> </form> </body> </html> |
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | using System; // using AccesoDatos; public partial class Cliente : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void btnConectar_Click(object sender, EventArgs e) { try { lblEstado.Text = ""; AccesoDatos.Conexion.IniciarSesion("127.0.0.1", "Queryable", "sa", "***"); lblEstado.Text = String.Format("{0}", "Se conecto exitosamente"); } catch (Exception ex) { lblEstado.Text = String.Format(ex.Message); } } protected void btnListar_Click(object sender, EventArgs e) { var cliente = new AccesoDatos.Orm.Cliente(); try { grilla.DataSource = cliente.Listar(); grilla.DataBind(); lblEstado.Text = String.Format("{0}", "Se listo exitosamentë"); } catch (Exception ex) { lblEstado.Text = ex.Message; } } protected void btnCrear_Click(object sender, EventArgs e) { var cliente = new AccesoDatos.Orm.Cliente(); try { cliente.IdCliente = Convert.ToInt16(txtIdCliente.Text); cliente.Descripcion = txtDescripcionCliente.Text; cliente.Sigla = txtSiglasCliente.Text; cliente.Crear(cliente); lblEstado.Text = String.Format("{0}", "Se creo exitosamente"); } catch (Exception ex) { lblEstado.Text = ex.Message; } } protected void btnListarById_Click(object sender, EventArgs e) { var cliente = new AccesoDatos.Orm.Cliente(); try { cliente = cliente.Listar(Convert.ToInt16(txtIdCliente.Text)); if (cliente != null) { txtDescripcionCliente.Text = cliente.Descripcion; txtSiglasCliente.Text = cliente.Sigla; } else { lblEstado.Text = String.Format("{0}", "No existia el cliente buscado"); } } catch (Exception ex) { lblEstado.Text = ex.Message; } } } |
Si pueden agregar/aportar mejoras y funcionalidad a estas clases, serán bienvenidas
de hecho éste código lo creo un MVP de Microsoft y yo le agregue algunas funcionalidades..
Parte 1 | Parte 2 | Parte 3 | Parte 4
Edit [2010/08/05]:
A pedido de JR, les subo un ejemplo práctico de las 3 capas con Firebird como Base de Datos, C# el lenguaje. Ya están incluidas dentro del proyecto el Data Provider y la BD de ejemplo. El password del fichero es www.devtroce.com, que lo disfruten!









en
en
en
Hola GeekZero. Antes que nada muchas gracias por este excelente post. Quería hacerte una pregunta. En la parte 1 del post dices que el código puede utilizarse desde VS2005 con el framework 2.0 en adelante, sin embargo yo bajé código ejemplo para Firebird y en alguno de los .cs aparece un using Linq. ¿El código de ese ejemplo puedo utilizarlo en VS2005 o no ? entiendo que LINQ es de VS2008 en adelante.
Gracias nuevamente. Marcelo
Hola Marcelo, pasa que el ejemplo con firebird lo agregue recientemente a pedido de uno de los lectores y ya no cuide ese detalle, pero el codigo que ves en la pagina esta basado en el 2.0, si se me escapo en algún lugar simplemente sacalo del using ya que no utilizo en las capas ninguna de las caracteristicas Linq
Gracias por tu pronta respuesta. Voy a probar sin el using y cualquier cosa te aviso. Saludos.
Geekzero, en GDatos dice
// asignar el string sql al command
var com = Comando(procedimientoAlmacenado);
La keyword VAR ¿no es de C# 3.0 ? no me compila en vs2005.
Gracias, Marcelo.
Asi mismo es de c# 3.0, originalmente cuando lo que subi estuvo para la version 2, pero tuvimos unos problemas con la db de wordpress y se perdieron algunos datos y tuve que reconstruir con lo que tenia, este tema lo hice casi completo de nuevo y como lo habia actualizado ya para mi vs 2008 quedaron algunos problemas como este, me es dificil hacerme de tiempo para reponer todo como estaba antes, pero prometo que cuando pueda lo iré haciendo..
Saludos, gracias por poner este ejemplo en la web. Mi pregunta es que porque solo puedo iniciar sesión si tengo al usuario sa con un password. He intentado iniciar sesión con un usurio que yo creo en sql server y no funciona, me marca: “Error de inicio en el usuario sa”. ¿Saben a que se debe?
Pongo el código tal cual y no sirve, mi usuario tiene todos los permisos, etc.
Conexion.IniciarSesion(“127.0.0.1″, “MyBD”, “myusuario”, “mypass”);
Y funciona tu login del sa desde el SSMS? puedes revisar en la clase SqlServer al momento de construir la cadena de conexion si todo esta bien..
Gracias por tu respuesta, si serve en el Management Studio. Mira este es el codigo que tiene la clase SqlServer para crear la cadena:
sCadena.Append(“data source=;”);
sCadena.Append(“initial catalog=;”);
sCadena.Append(“user id=;”);
sCadena.Append(“password=;”);
sCadena.Append(“persist security info=True;”);
sCadena.Append(“user id=sa;packet size=4096″);
sCadena.Replace(“”, Servidor);
sCadena.Replace(“”, Base);
sCadena.Replace(“”, Usuario);
sCadena.Replace(“”, Password);
no se si sea por esta linea:
sCadena.Append(“user id=sa;packet size=4096″);
¿Tendrás idea?
Gracias por tu respuesta, si serve en el Management Studio. Mira este es el codigo que tiene la clase SqlServer para crear la cadena:
sCadena.Append(“data source=;”);
sCadena.Append(“initial catalog=;”);
sCadena.Append(“user id=;”);
sCadena.Append(“password=;”);
sCadena.Append(“persist security info=True;”);
sCadena.Append(“user id=sa;packet size=4096″);
sCadena.Replace(“”, Servidor);
sCadena.Replace(“”, Base);
sCadena.Replace(“”, Usuario);
sCadena.Replace(“”, Password);
no se si sea por esta linea:
sCadena.Append(“user id=sa;packet size=4096″);
¿Tendrás idea?
El problema es como armas la cadena de conexion, el metodo replace no esta bien utilizado. Fijate como esta en el original y como se utiliza el StringBuilder. Con eso ya solucionarias el problema
La conexion se abre solo cuando ejecutas algun proceso de lectura o escritura, y se cierra cuando finaliza.. no hace falta que escribas en capa alta eso..
Saludos mencionaste esto hace algunos post pero ya analize el código y no veo en ninguna parte que abra la conexión antes de ejecutar/leer algo y al terminar la cierre.
Por ejemplo aqui:
// Ejecuta un query sql.
public int EjecutarSql(string comandoSql)
{ return ComandoSql(comandoSql).ExecuteNonQuery(); }
Esque he tenido problemas con mis proyectos anteriores que se conectaban remotamente y no cerraba la conexion al ejecutar comandos. Espero con este gran ejemplo que publicas ya no tenga este tipo de problemas.
Hola, me sirvió mucho este ejemplo y lo utilizé para un proyecto escolar. Pero, me gustaria me pudieran ayudar.
Desde este boton “Guardar” hago lo siguiente cada que se guarda un registro…..
private void btnAgregar_Click(object sender, EventArgs e)
{//Agrega un producto al detalle del pedido
int canti = Convert.ToInt32(txtCantidad.Text);
idproducto = gridProductos.CurrentRow.Cells[0].Value.ToString();
producto = gridProductos.CurrentRow.Cells[1].Value.ToString();
tamaño = gridProductos.CurrentRow.Cells[2].Value.ToString();
precio = gridProductos.CurrentRow.Cells[3].Value.ToString();
descripcion = gridProductos.CurrentRow.Cells[5].Value.ToString();
//Se llama al metodo AgregarProducto enviandole el producto a guardar
idOrdenPedido = AgregarProducto(idproducto, producto, tamaño, precio, descripcion, canti);}
Tengo este método para insertar un registro ……
public int AgregarProducto(string idproducto, string producto, string tamaño, string precio, string descripcion, int cantidad)
{
var pedido = new Pedidos();
pedido.IdProd = Convert.ToInt32(idproducto);
pedido.nomProducto = producto;
pedido.tamano = tamaño;
pedido.precioProducto = Convert.ToDecimal(precio);
pedido.descripcion = descripcion;
pedido.cantidad = cantidad;
pedido.subtotal = Convert.ToDecimal(pedido.cantidad * pedido.precioProducto);
// Envia los datos al metodo Insertar Productos y regresa el id de OrdenPedido
return Convert.ToInt32(pedido.insertarProdSelec(pedido));
}
y le envia los parametros a este otro metodo que ejecuta el procedimiento almacenado……
public int insertarProdSelec(Pedidos pedido)
{
int idObtenido = Convert.ToInt32(Conexion.GDatos.Ejecutar(“paOrdenPedido_Agregar”,
pedido.IdProd,
pedido.nomProducto,
pedido.tamano,
pedido.precioProducto,
pedido.descripcion,
pedido.cantidad,
pedido.subtotal, 7),);
return idObtenido;
}
Este es mi procedimiento almacenado
ALTER PROCEDURE paOrdenPedido_Agregar
@idOrdenPedido int OUTPUT,
@IdProd int,
@nomProducto nvarchar(50),
@tamano nvarchar(50),
@precioProducto decimal (18,0),
@descripcion nvarchar(100),
@cantidad int,
@subtotal decimal (18,0)
AS
INSERT INTO tbDetallePedido
(idProducto, nomProducto, tamano, precioProducto,
descripcion, cantidad, subtotal)
values (
@IdProd, @nomProducto, @tamano, @precioProducto,
@descripcion,@cantidad, @subtotal);
SELECT @idOrdenPedido = SCOPE_IDENTITY()
RETURN
NOSE QUE ESTOY HACIENDO MAL NO ME DEVUELVE NADA
O debo usar el
public object TraerValorOutput(string procedimientoAlmacenado)
{
var com = Comando(procedimientoAlmacenado);
com.ExecuteNonQuery();
Object resp = null;
// recorrer los parametros del SP
foreach (IDbDataParameter par in com.Parameters)
// si tiene parametros de tipo IO/Output retornar ese valor
if (par.Direction == ParameterDirection.InputOutput || par.Direction == ParameterDirection.Output)
resp = par.Value;
return resp;
}
Hola Sussy, puede ser variante aun la respuesta, pero estimo que una posibilidad de error se da con tu llamada al SCOPE_IDENTITY, prueba con @@Identity y luego cuentame que tal te fue..
como puedo enviar la variable @idOrdenPedido dede c# esa parte no me queda muy clara, y como se envia. Bueno de acuerdo a esta metodologia ya que encontre un ejemplo asi:using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
{
conn.Open();
SqlCommand command = new SqlCommand(“sp_ContactoInsert”, conn);
command.CommandType = CommandType.StoredProcedure;
SqlParameter paramId = new SqlParameter(“Id”, SqlDbType.Int);
paramId.Direction = ParameterDirection.Output;
command.Parameters.Add(paramId);
command.Parameters.AddWithValue(“Nombre”, nombre);
command.Parameters.AddWithValue(“Direccion”, direccion);
command.Parameters.AddWithValue(“FechaNacimiento”, fechaNacimiento);
int rowsAffected = command.ExecuteNonQuery();
if (rowsAffected > 0)
{
return Convert.ToInt32(command.Parameters["Id"].Value);
}
else
return -1;
}
y con este procedimiento almacenadoALTER PROCEDURE dbo.sp_ContactoInsert
@Id int OUTPUT,
@Nombre varchar(50),
@Direccion varchar(50),
@FechaNacimiento DateTime
AS
INSERT INTO Contactos
(NombreCompleto
,Direccion
,FechaNacimiento)
VALUES (@Nombre,
@Direccion,
@FechaNacimiento);
SELECT @Id = SCOPE_IDENTITY()
RETURN
y funciona bien, pero claro que tiene todo el codigo en la forma, como se puede implementar un ejemplo parecido a este pero aplicado a esta metodologia.
que devuelva el id identitity.
Bueno muchas gracias!!!
Ya creo comprender tu pregunta, le he respondido lo mismo a racman. Debes utilizar el metodo TraerValorEscalar, este es el ejemplo que le di en su caso:
Hola Jorge, definitivamente debes agregar una referencia, das clic derecho sobre tu proyecto forms, agregar referencia, en la pestaña proyectos, elijes la bibioteca de clases y generas de nuevo la solucion..
Disculpa tengo ambos proyectos (windows forms) y libreria de clases dentro de la misma solución. Pero cuando en un form pongo:
using AccesoDatos;
using AccesoDatos.Orm;
No me los admite, ¿es necesario agregar la referencia o cual es motivo?
Una sola vez, hasta cerrar la aplicación. Cada vez que ejecutas algo se conecta y se desconecta al terminar, pero no lo controlas en alto nivel. El login inicial solamente sirve para cargar los valores de conexion que se usaran durante este abierto tu app..
¿En que evento de mi aplicacion debo cerrar la conexión con la base de datos?
¿Que pasa si se apaga el equipo o se cierra la aplicacion por algun fallo, se mantendría una conexión activa?
Disculpa tantas preguntas pero es algo que me he preguntado durante mucho tiempo y no he encontrado nada, pero al parecer tu tienes la respuesta =)
La conexion se abre solo cuando ejecutas algun proceso de lectura o escritura, y se cierra cuando finaliza.. no hace falta que escribas en capa alta eso..
En mi login solo realizo el
Conexion.IniciarSesion(“127.0.0.1″, “Queryable”, “sa”, “***”);
¿Y en todas mi clases y formas ya no tengo que volver a Iniciar Sersion?
¿debo conectarme antes de ejecutar un comando y desconectarme cuando se ejecute? ¿O no es necesario?
Gracias. Excelente aporte.
Nuevamente mil gracias por tu tiempo. He bajado el ejemplo y estoy tratando de hacerlo andar en un boton de un form, pero no logro pasar el resultado de lo que devuelve el metodo listar() a un datasource de una grilla, pero evidentemente es un problema mio.
Mil gracias nuevamente.
Hola GeekZero.
Otra vez miles de gracias por la respuesta.
Utilizando tu ejemplo, he hecho esto, a ver si esta bien.
He creado una clase que ha he llamado ColeccionClientes
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AccesoDatos.Orm;
namespace BibliotecaDeClases
{
public class ClaseColeccionClientes :List
{
}
}
He tenido que hacer el using de AccesoDatos.Orm ya que necesito la definicion de la clase Cliente que tu haz hecho.
Y he hecho un mentodo en Cliente para llenar esta coleccion
public BibliotecaDeClases.ClaseColeccionClientes LlenarColeccion()
{
var ListaClientes = new BibliotecaDeClases.ClaseColeccionClientes();
DataSet prueba = new DataSet();
prueba = Conexion.GDatos.TraerDataSet(“slcCliente”);
// MessageBox.Show(prueba.TableName.ToString());
foreach (DataRow row in prueba.Tables[prueba.Tables.Count - 1].Rows)
{
Cliente uncliente = new Cliente();
uncliente.IdCliente = Convert.ToInt16(row["idCliente"].ToString());
uncliente.Descripcion = row["DescripcionCliente"].ToString();
uncliente.Sigla = row["Siglas"].ToString();
ListaClientes.Add(uncliente);
}
return ListaClientes;
}
Le he agregado un boton a la aplicacion y he puesto este codigo
Cliente uncliente = new Cliente();
grilla.DataSource = uncliente.LlenarColeccion();
donde desde luego veo lo mismo que tu pones en el boton LISTAR, pero de esta manera obtengo los datos yo y los puedo manejar, con un datatable que es lo que devuelve Cliente.Listar() no se como recorrerlos y obtenerlos a los datos.
Nuevamente muchisimas gracias por tu tiempo y tu respuesta. Sos realmente muy amable.
Fijate en esto, te pondré un ejemplo simple sin conexion a BD, lo que intentaré es ilustrarte el uso del retorno de un listado de un tipo de clase. No debes crear ninguna clase extra para ello, simplemente el tu clase base tendrá un método que retornará un listado de su mismo tipo, y luego será consumido en algun lugar.
En este ejemplo veras una clase persona con 3 atributos, los cuales cargaré por código manualmente (y tu lo harás a partir de algun DataTable) luego retornare un listado de personas y en el metodo recorrer listado invocaré al método que retorna la lista, lo recorreré y se imprimirá en la consola del VS.
Hola. Ante todo mil gracias por este ejemplo que realmente sirve y mucho. En mi caso estoy empezando con C# y programacion en n capas, asi que estoy viene de maravillas. Pero como buen principiante, tengo una duda que estoy seguro que esta resuelta en el ejemplo y no la puedo ver.
Hay muchisimos caso en una aplicacion sea o no en capas, donde vos tenes que llamar a un store procedure, y con los registros que te devuelve hacer algun tipo de operacion, recorrelos, etc.
Dento de los metodos que vos tenes con cual puedo hacerlo, porque por ejemplo el traerdatatable me devuelve una tabla y tendria que recorrer fila por fila y columna por columna. Normalmente lo que hago es recorrer las filas y ya se como se llaman las columnas (campos de la tabla), ya se aca son objetos. Con un SqlDataReader podria hacerlo como te digo, pero no usaria todo el potencial de tu ejemplo.
Espero se haya entendido.
Aca te dejo el ejemplo que te comento, pero hecho no utilizando el potencial de tu codigo.
public override ClaseLegajo ObtenerLegajo(int PNroLegajo)
{
SqlConnection C = this.ObtenerConexion();
SqlDataReader DR = this.EjecutarQuery(“Select nro_legajo,nombre from per_legajo where nro_legajo=” + PNroLegajo, C);
ClaseLegajo UnLegajo = null;
if (DR.HasRows)
{
DR.Read();
UnLegajo = new ClaseLegajo();
UnLegajo.NroLegajo = Convert.ToInt32(DR["nro_legajo"]);
UnLegajo.Nombre = DR["nombre"].ToString();
UnLegajo.Agentes = ObtenerColeccionAgente(Convert.ToInt32(DR["nro_legajo"]));
UnLegajo.Agentes.AsignarLegajo(UnLegajo);
}
DR.Close();
C.Close();
return UnLegajo;
}
De esta manera al menos a mi se me hace mas facil el acceso a los datos. Pero me gustaria utilizar tu codigo que es rapidisimo y efectivo.
Desde ya mil gracias.
Hola Cdlesca, si he entendido bien quieres un metodo que devuelva un conjunto de objetos del tipo de tu clase creada, en este caso legajo. Para ello tienes varias posibilidades.
Espero te sirva de ayuda ésto, si necesitas más ayuda hazmelo saber.
Error mi conexión a la base de datos
Conexion.IniciarSesion(“SUSY-PC\\SQLEXPRESS”, “bdEjemploCapas”, “SUSY-PC\\SUSY”, ” “);
me dice un error, esta por autentificación de windows y no tiene pass para entrar a la bd.
En otros ejemplod me conecto de forma muy similar pero aqui no se proque no me deja
GeekZero, crees q seria bueno iniciar otro hilo, con las dudas del post… pues ya esta como largo…
Para que sea mas legible podemos responder solo al primer nivel.. o puedes crear un hilo en el foro que tiene mucho mas espacio ya que aprovecha casi toda la resolución de la pantalla
Si te devuelve cero deberías verificar tu SP, lo haz probado con los mismos datos desde tu SQL? o cambiado de valores a los parametros? si estás seguro que algo no funciona bien sube parte de tu proyecto en el foro para intentar replicar la falla.
Hola que tal:
Tengo el siguiente problema, ya tengo un procedimiento almacenado en el cual consultare un nombre de usuario y password filtrado por un numero de sucursal, como le hago para enviarle los parametros porque no me devuelve nada tu ejemplo, ni siquiera con un solo parametro.
Ejem:
grilla.DataSource = Usuario.Validar_Usuario(“aacalvillo”,12345,400);
no devuelve nada.
Saludos
Hola aacalvillo, con los datos que me pasas no puedo saber que estas haciendo, asumo que Usuario es alguna clase y Validar_Usuario uno de sus metodos.
Como no veo el código que hay dentro de tu método no puedo decirte que está mal. Sería bueno que te expliques un poco mejor, que querés cargar en la grilla o que valores esperas que retorne tu procedimiento.
Como va a ser un poco largo los datos que necesitas pasarme, sería bueno que crees un hilo en el foro ya que hay más espacio para ello, con un tu código C# y T-SQL podría ayudarte con gusto..
Perdon por la falta de datos, efectivamente Usuario es una clase, solo le cambie de nombre a la que tienes de ejemplo llamaca clientes, todo es lo mismo solo que quiero mandarle un par de parametros pero estoy viendo que si devuelve el resultado, el problema es que se vuelve null el return una ves que la clase slcClientebyId lo retorna para llenar la grilla.
que podre hacer??
Y comprobaste desde tu SQL Management Studio ese SP te devuelve valores con los mismo parametros?
Sera para validacion de usuarios del sistema, no a la bd, la consulta debe retornarme los datos del usuario y sera para validar si el password es correcto.
Pero el error era mio no note que lo que me retornaba no era un datatable por eso no mostraba nada en la grilla.
Saludos
necesito una ayuda…
tengo un procedimiento q recibe dos parametros unos de entrada y otro de salida, como puedo hacer el llamado a este sp
int salida;
Conexion.GDatos.TraerDataSet(“CalcTasa”, ["Entrada", salida]);
// proceso salida
Hola Racman, si tienes un solo output con esto puedes capturarlo:
el codigo me marca error, me dice que falta un parametro…
Procedure or function ‘CalcTasa’ expects parameter ‘@Salida’, which was not supplied
desde SQL ejecuto asi el SP.
DECLARE @Salida int
EXECUTE [dbo].[CalcTasa] ‘Entrada’,@Salida OUTPUT
select @Salida
Racman disculpa que tarde en responderte, estoy muy ocupado con cosas del trabajo.
Por lo que veo en tu SP recibes 2 parámetros y 1 es de salida, para invocarlo debes enviarles ambos parámetros aunque no hagas nada dentro del SP con el parámetro de salida, así como lo hiciste con tu código TSQL.
Desde C# puedes hacer lo siguiente:
o pasale otro valor si lo necesitas.
No te preocupes por la demora GeekZero, pienso q todos debemos estar agradecidos por compartir tu conodimiento.
hice la prueba como tu me recomendaste y me retorna cero, adjunto un ejemplo de la forma como lo trabajo siempre, pues de pronto es q no me he hecho entender… y pues la verdad me llama la atención la forma como invocas los procedimientos pues ahorra la escritura de mucho codigo..
este es la forma como invoco el sp
SqlConnection conn = new SqlConnection();
conn = ObtenetConexionSQL(false);
SqlCommand comando = new SqlCommand();
comando.CommandType = CommandType.StoredProcedure;
comando.CommandText = “CalcConsec”;
comando.Connection = conn;
comando.Parameters.AddWithValue(“@ConsecNombre”, “test”);
comando.Parameters.Add(“@Consecutivo”, SqlDbType.Int);
comando.Parameters["@Consecutivo"].Direction = ParameterDirection.Output;
comando.ExecuteNonQuery();
int salida = Convert.ToInt16(comando.Parameters["@Consecutivo"].Value);
MessageBox.Show(salida.ToString());
Primeramente muchas gracias por el aporte… esta genial… pero como de costumbre la conexion es SQLServer… estoy tratando de empezar a explorar bases de datos libres para ser mas concreto MySql… entiendo que habria que agregar un clase MySql.cs con todas sus caracteristicas… pero como ya lo dije estoy empezando… te pediria el favor de que subas la clase respectiva para el MySql y tambien.. que es lo que cambia en la clase Conexion para conectarse a ella… o bien porfavor me lo pasas a mi correo adisbravo@hotmail.com
Saludos y Bendiciones…!!!!
Fijate que esta colgado un ejemplo con Firebird, a partir de FB y MsSQL podras crear tu propia clase para MySQL
, exitos..
Muy bien.. acabo de terminar la clase para un servidor MySql… si la necesitan o quieren mirarla.. la pueden bajar desde este enlace… http://www.gigasize.com/get.php?d=y1qqmytgzvf
Una cosa mas… para que se conecten… necesitan cambiar la clase conexion este codigo:
GDatos = new SqlServer(nombreServidor, baseDatos, usuario, password);
por este otro:
GDatos = new MySqlServer(nombreServidor, baseDatos, usuario, password);
Espero aporte un poquito con esto… de verdad que me ha servido de mucho este post… mi agradecimiento nuevamente a el o los impulsores…!!!
Excelente Adis, lo haz logrado
fue sencillo no? Gracias por compartir lo que haz hecho con el resto de los lectores..
Excelente codigo, gracias…
tengo una dudo, aca cuando cambio de servidor pues simplemente hago el cambio en al linea de codigo
AccesoDatos.Conexion.IniciarSesion(“127.0.0.1″, “Queryable”, “sa”, “***”);
pero es necesario modificar el codigo, para el caso que tenga mi ejecutable final, y por ejemplo mi cliente cambie de servidor como puedo hacer esto, sin modificar el codigo… he leido algo q debo manejar un archivo de configuiracion pero la verdad no se como se maneja asi, gracias
Hola Racman, esto lo puedes resolver de muchas maneras, pero la que tu mencionas puedes configurarlo asi:
1. Das clic derecho sobre tu proyecto, propiedades, en la lengueta de configuración agregas un recurso llamado Host con el valor 192.145.33.21 y otro BaseDato con valor DBtroce como ejemplos.
2. Para consultar esos valores:
A tu usuario y pass dejalo cargar al user, mejor si ellos se loguean con usuarios de la BD y no de tablas, solo que deberas administrar como dios manda tu motor..
hola amigo estoy intentando descargar el ejemplo que has subido al internet desde el link que indicas pero resulta que el link no existe porfavor haber si lo subes denuevo o me lo podrias enviar a mi correo valdezalva@hotmail.com .
Muchas gracias!!
Ya está nuevamente en línea, justo lo intentaste cuando los servidores estaban en mantenimiento nada más, pruebalo nuevamente
Hola que tal, muy buen articulo, realmente estaba buscando algo de practica, una consulta, éste proyecto puede ser adaptado para que haga uso de LinqToSql en plataforma web? Gracias.
Hola Francisco, con respecto a tu pregunta, puedes crear un proyecto en capas con LinqToSql (un conocido mío lo está haciendo) pero vas a escribir todo de nuevo, éstas líneas no te servirán, pero para inspiración es posible que si.
Muy bueno ,yo tambiem hize uno pero aun me falta algo de codigo sql ;esto es
por que me estoy iniciando en la programacion
Perfecto. ya quedo
solo hacia falta agregar el alias de la DB en el archivo alias
ya se logro la conexion a la base de datos.
voy a revisar el proyecto.
gracias de nueva cuenta
Ya descompacte el archivo en una carpeta del disco duro
(d:proyectodevtroce)
abro el proyecto, ejecuto y al intentar conectar me muestra una ventana con el siguiente mensaje
I/O error file "Devtroce"
Error while trying to open file
revisando el codigo veo que el error se esta dando en la siguiente linea de codigo
AccesoDatos.Conexion.IniciarSesion("127.0.0.1","Devtroce","SYSDBA","masterkey");
que estoy omitiendo?
¬¬
Hola JR
Notaste que no tenes la DB "Devtroce" ??
Si GeeZero te la paso en link de Descarga lo mas seguro es que falte
configurar el aliases.conf con la ruta donde se encuentra la DB.
En tu caso seria algo asi
– Dentro del aliases.conf –
'Devtroce = D:proyectodevtroceDevtroce.FDB'
Efectivamente es como te comenta Orland, necesitas tener instalado el Firebird y su servicio debe estar arriba, además de configurar el aliases.conf como lo indicaba.
La BD lo coloque dentro del proyecto AccesoDatos, en la carpeta data, copialo donde quieras y asignale ese path al aliases
Del apuro me he olvidado eso, el pass es
Cordial saludo,
me podrias indicar cual es el password de este archivo que hace referencia a un ejemplo donde utilizas como motor de base de datos a Firebird
Descargalo de aqui: http://www.gigasize.com/get.php?d=0r5slgvb2zb
habiar colocado esto pero no entiendo cual es el password
5 Agosto 2010 en 11:49
Del apuro me he olvidado eso, el pass es <pre lang="devtroce"> ;www.devtroce.com
Correjido el bug, también esta en el post el password..
Muchas gracias por tu ayuda
Excelente, muy rapida atencion.
Mira, estoy iniciando un proyecto donde la base de datos esta en Firebird, y debo de realizarlo en un proyecto de 3 capas. pero desafortunadmente no logro echarlo a andar. y al llegar a este portal en encontre esta infromacion que es de de gran ayuda.
De ser posible que tengas algun codigo para implementar lo de las 3 capas para una base de datos firebird, seria formidable.
el tipo de aplicacion debe de ser de escritorio, base de datos en firebird y programacion en C# o Vb.Net, cualquier ayuda es bienvenida.
La idea de tener en algun archivo descargable el proyecto que expones en este portal, es verlo funcionando con una base de datos SQLServer, pero el objetivo final es crear un nuevo proyecto para poder utilizarla en una base de datos firebird.
Gracias, por la atencion al mensaje enviado.
Fijate JR, te he puesto un ejemplo Desktop ya con la clase editada para funcionar con Firebird, como dije en el post, ya incluye una copia de la BD que use y el Data Provider.
Disculpa que he hecho un ejemplo algo chapucero, no está muy bien diseñada la interfaz, y no tiene casi comentarios, pero creo que es suficiente para comprender el concepto.
Descargalo de aqui: http://www.gigasize.com/get.php?d=0r5slgvb2zb
Lo he puesto en este servidor para no usar el ancho de banda innecesariamente y así llevar un registro de las descargas del ejemplo también
Cuentanos que tal te va!
Gracias por la ayuda. he descargado el archivo.
tiene contraseña el archivo compactado, no puedo descompactarlo.
Saludos, y gracias de nuevo.
Excelente codigo, de gran ayuda.
Pero no logro poner todo el codigo en un proyecto para trabajar con el.
No podrias por favor poner el proyecto en algun archivo compactado para poderlo descargar y ver como deberia de estar el proyecto?
Que tal JR, normalmente debes ponerlo en un proyecto por separado dentro de la misma solucion, pero puedes hacerlo tambien dentro del mismo proyecto si sabes que usarás uno solo. Realmente a este codigo yo le he agregado más variantes tambien, para que plataforma quieres? WEB o Desktop? en el caso de WEB lo he cambiado en partes importantes para hacer uso de variables de SESSION en las capas de acceso a datos.. Si me pasas esta info puedo subirte un ejemplo apenas tenga tiempo para armarte uno..