domingo, 15 de noviembre de 2009

[ADO.NET] Parte 1 - Recuperar Información Sql Server

 

Introducción


He notado que a veces faltan ejemplo integradores sobre el uso de ciertos aspectos que a primera vista parecen simple, pero al no encontrase en uso de forma integradora pueden resultar algo difíciles de captar las ideas, especialmente cuando se comienza en el aprendizaje.

La objetivo de este articulo es mostrar como hacer so de ado.net paso a paso en un ejemplo concreto utilizando varios métodos de consultas y trabajo de la información obtenida

 

Algunas aclaraciones antes de comenzar


Si bien la explicación del ejemplo se centrara en el uso de ado.net bajo lenguaje c#, los ejemplos podrán descargarse también en vb.net

Las explicación del articulo aplica a ambos lenguajes sin problemas.

Con respecto al diseño del ejemplo por ahí algunas aclaraciones previas podrá facilitar la comprensión.

Se visualizaría que en el ejemplo se han declarado dos clases que por ahí no son familiares, estas llevan el nombre: ContactoDAL y ContactoEntity.

Para el que no conozca el DAL (Data Access Layer) en realidad apunta a separa en capas la aplicación para dividir las responsabilidades y poder así encapsular y abstraer funcionalidad facilitando la reutilización.

En este caso en particular aplique este mismo concepto pero no lo puse en un proyecto nuevo, simplemente para no complicar el ejemplo, es por eso que tanto estas clases como el formulario están en el mismo proyecto.

También verán una clase que termina con la palabra entity, esta básicamente representa la entidad del dominio, y define las propiedades que posee la tabla de contactos, esta entidad será la intermediaria entre la funcionalidad de la DAL y la presentación. Esta clase evitara que a la presentación le lleguen objetos que claramente son de datos.

Aunque vale aclarar que en este ejemplo al estar contenido en un solo proyecto se pierde un poco el objetivo de abstraer a la presentación de componente de datos, pero igualmente esta es una buen técnica para mantener el código prolijo.

 

1 - Recuperar un conjunto de datos (DataReader)


La primera operación que será utilizada será la de recuperar todos los ítems de una tabla y cargar una grilla con ellos.

Para esta operación hay dos formas para acceder a los datos, por medio de:

  • DataReader
  • DataSet

Para los DataReader es que se hace uso de la clase con sufijo “entity” de esta forma se cargan los datos en estas entidades evitando pasar el reader a la presentación, lo cual no es nada aconsejable.

Algo importante para contar acerca de los reader es que estos necesitan mantener la conexión a al db abierta durante el procesamiento (o lectura de los registros que se están recuperando), es por eso que usar clases de entidades ya que se procesa el reader en un tiempo muy corto y luego se cierra. Hay que destacar que lo reader en acceso secuencial de lectura son mas rápido que los dataset.

Para el dataset, se hace uso de un DataSet tipado, en el proyecto lleva el nombre de “dtoContacto”, este permite tener una estructura definida, similar a la que brinda “ContactoEntity”.

En la clase ContactoDAL, se encuentran dos métodos “GetAll” y “GetAllFromDataSet”.

Empezaremos explicando como hacer uso de DataReader.

public static List<ContactoEntity> GetAll()
{
    string sql = @"SELECT [IdContacto]
                          ,[Nombre]
                          ,[Apellido]
                          ,[FechaNacimiento]
                          ,[Localidad]
                          ,[Calle]
                          ,[Numero]
                      FROM Contacto";

    List<ContactoEntity> list = new List<ContactoEntity>();

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        SqlCommand command = new SqlCommand(sql, conn);

        conn.Open();

        SqlDataReader reader = command.ExecuteReader();

        while (reader.Read())
        {
            list.Add(LoadContacto(reader));
        }

        return list;
    }

}

> Creación del objeto de conexión a la base de datos (línea 14): Este siempre será el primer paso ya que es necesario definir el objeto que permitirá establecer el contacto con la base de datos. Para realizar la tarea se necesitara de un string de conexión, para mas detalles ver “Cadena de conexión”.

Algo interesante que observaran es el uso de la sentencia using, el objetivo de esta es permitir delimitar la sección en que estará disponible un objeto, o sea el ámbito en el cual la instancia será usada, verán como al final cuando se termina de utilizar los objetos no se realiza un cierre de la conexión o un Dispose de los objetos, es justamente el bloque using el que hará esto por nosotros.

> Objeto Command (línea 17): este objeto permitirá unificar la consulta sql de selección que vamos a utilizar con la conexión a la base de datos que establecimos en el paso anterior.

El objeto command posee la funcionalidad para ejecutar la consulta que se ha creado, ya sea esta para insertar o actualizar la información, o como en este caso para recuperarla.

> Ejecución de la consulta (línea 21): el objeto command posee un método de nombre ExecuteReader(), el cual devolverá como resultado un objeto del tipo SqlDataReader.

> Lectura de los datos devueltos (líneas 23-26): al tratarse de un grupo de registros los que se recuperaran de la consulta es necesario realizar un ciclo por cada uno de ellos realizando la transformación de los datos para adecuarlos al objeto definido como entidad de negocio de la aplicación, en este caso “ContactoEntity”

El método Read() del objeto SqlDataReader tiene dos funcionalidades básicas, devuelve un true o false según se encuentren registros para leer, y además posiciona el cursor el el siguiente registro habilitado, es por eso que el while cumple la función ideal para recorrer cada ítem del objeto DataReader.

> Transformación de los datos del reader a la entidad (línea 25): esta operación se ha encapsulado en un método separado ya que es una operación que será reutilizada:

private static ContactoEntity LoadContacto(IDataReader reader)
{
    ContactoEntity contacto = new ContactoEntity();

    contacto.IdContacto = Convert.ToInt32(reader["IdContacto"]);

    contacto.Nombre = Convert.ToString(reader["Nombre"]);
    contacto.Apellido = Convert.ToString(reader["Apellido"]);

    contacto.FechaNacimiento = Convert.ToDateTime(reader["FechaNacimiento"]);

    contacto.Localidad = Convert.ToString(reader["Localidad"]);
    contacto.Calle = Convert.ToString(reader["Calle"]);
    contacto.Numero = Convert.ToInt16(reader["Numero"]);


    return contacto;
}

Como se observara en el bloque de código este método crea una instancia nueva de la entidad que estamos utilizando, luego asigna a cada propiedad la columna que le corresponde del registro que se esta leyendo en ese momento, el cual se ha pasado como parámetro al método, y por ultimo retorna el objeto entity con los datos para ser asignado a la colección de “ContactoEntity”.

 

2- Recuperar un conjunto de datos (DataSet)


Esta operación tendrá mucho en común con la anterior solo diferirá en la utilización algunos objetos distintos ya que se hará uso de un DataSet, (en este caso tipado) para cargar los datos

 

public static dtoContacto GetAllFromDataSet()
{
    string sql = @"SELECT [IdContacto]
                          ,[Nombre]
                          ,[Apellido]
                          ,[FechaNacimiento]
                          ,[Localidad]
                          ,[Calle]
                          ,[Numero]
                      FROM Contacto";

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        SqlCommand command = new SqlCommand(sql, conn);

        SqlDataAdapter da = new SqlDataAdapter(command);

        dtoContacto contactos = new dtoContacto();

        da.Fill(contactos, "Contacto");

        return contactos;
    }

}

Como se observara en el código los dos primeros pasos son coincidentes con la operación anterior que utilizaba DataReader para la obtención de los datos, se detallara a continuación las diferencias.

> Creación del adaptador (línea 17): Este objeto DataAdapter proporcionara la herramienta principal para poder cargar un objeto del tipo DataSet.

Como ser observara el constructor del objeto SqlDataReader en este caso recibe al objeto Command como parámetro, pero debe comentarse que no es la única alternativa, en este caso se uso el command para mantener una uniformidad en la codificación, pero podría haber pasado como parámetro la consulta sql y el objeto conexión directamente al constructor del DataAdapter, de esta forma ya no se necesitara mas del objeto Command.

> Creación y llenado de los datos (líneas 19-21): La definición del dataset tipado se encuentra en el archivo de nombre “dtoContacto.xsd”, al inspeccionar el archivo se notara que este contiene un DataTable de nombre “Contacto” y la definición de las columnas, las cuales coinciden con las de la tabla de la base de datos.

Nota: cuando se crea un DataSet Tipado lo mas común es que se agregue de forma automática un TablaAdapter, en este caso se removió dejando la entidad lo mas simple posible.

El método Fill() del DataAdapter realizara la ejecución y carga de los datos en el DataSet Tipado, al cual además le indicamos cual es el DataTable que se estará cargando. Debe recordarse que un DataSet puede contener mas de un DataTable, en este caso posee solo uno, pero podría haber mas en otros casos.

Nota: al diferencia del objetos Command el SqlAdapter no requiere la apertura previa de la conexión, es por eso que la línea conn.Open() no esta presente. El DataDapter realiza la apertura, utilización y cierre de la conexión de forma automática

 

3 – Recuperar un solo registro (DataReader)


A diferencia la la operación en donde recuperábamos todo la información de una tabla, en este caso se remarcan dos puntos

- la utilización de parámetros en la consulta

- la no utilización del while para recorrer los datos provenientes de la consulta

 

public static ContactoEntity GetById(int Id)
{
    string sql = @"SELECT [IdContacto]
                          ,[Nombre]
                          ,[Apellido]
                          ,[FechaNacimiento]
                          ,[Localidad]
                          ,[Calle]
                          ,[Numero]
                      FROM Contacto
                      WHERE IdContacto = @Id";

    ContactoEntity product = null;

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        SqlCommand command = new SqlCommand(sql, conn);
        command.Parameters.AddWithValue("Id", Id);

        conn.Open();

        SqlDataReader reader = command.ExecuteReader();

        if (reader.Read())
        {
            product = LoadContacto(reader);
        }

        return product;
    }
}

> Creación del parámetro de la consulta (línea 19): como se observa el objeto Command posee una propiedad que permite definir los parámetros en la consulta, es allí donde serán agregados, y hay diferentes formas de hacerlo, la mas practica y directa para crear parámetros simples es utilizando el método AddWithValue().

Pero debe remarcarse un punto importante en el uso de este método, como se observara en ningún momento se define un tipo de dato para el parámetro, lo cual parecería hasta mágico como lo infiere, pero no es así, para que esto funcione correctamente el tipo de la variable que se utiliza debe ser del tipo correcto, en este caso el “Id” es del tipo int, el cual coincide con el tipo de la columna “Id” de la tabla en la base de datos, es por esto que todo es resulto fácilmente.

Por ejemplo, si el parámetro será una fecha la variable usada en el método AddWithValue, debería ser también del tipo fecha, o en su defecto se tendría que convertir (castear) al tipo DataTime. En definitiva el método para agregar parámetros es simple de usar pero requiere ciertos cuidados a tener en cuenta, ya que de otra forma no podrá determinar de forma dinámica el tipo de datos del parámetro.

> Lectura del registro (línea 25-28): a diferencia del proceso en donde se leían un grupo de registros, en este solo nos interesa uno solo, es por eso que al reemplazar el while por un simple if, este cumple la misma funcionalidad, el Read() del DataReader devuelve true si hay registro, y además posiciona el cursor en el mismo para su lectura.

Luego se reutiliza el método que devolverá la entidad completa, y esta es retornada como resultado del método.

 

4 – Recuperar un solo registro (DataSet)


A diferencia el método en donde se recuperaba un conjunto de registros aquí hay variantes

- se utiliza un parámetro en la consulta

- se devuelve un solo registro del DataTable y no el DataSet completo

public static dtoContacto.ContactoRow GetByIdFromDataSet(int Id)
{
    string sql = @"SELECT [IdContacto]
                          ,[Nombre]
                          ,[Apellido]
                          ,[FechaNacimiento]
                          ,[Localidad]
                          ,[Calle]
                          ,[Numero]
                      FROM Contacto
                      WHERE IdContacto = @Id";

    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
    {

        SqlCommand command = new SqlCommand(sql, conn);

        SqlParameter param = new SqlParameter("Id", SqlDbType.Int);
        param.Value = Id;
        command.Parameters.Add(param);

        SqlDataAdapter da = new SqlDataAdapter(command);

        dtoContacto contactos = new dtoContacto();

        da.Fill(contactos, "Contacto");

        if (contactos.Contacto.Rows.Count > 0)
            return contactos.Contacto.Rows[0] as dtoContacto.ContactoRow;
        else
            return null;
    }
}

> Creación del parámetro de la consulta (línea 18-20): a modo de ejemplo en este caso se ha utilizado una técnica distinta, en donde se define explícitamente cual es el tipo de datos del parámetro.

Se crea el objeto SqlParameter, pasando en el constructor el nombre y tipo de dato del parámetro, luego a la instancia se le asigna el valor, y por ultimo se agrega a la colección de parámetros del objeto Command

> Determinar si se encontró el registro, y retorno del ContactRow (lineas 28-31): Como en este caso lo que se carga es un Datset completo, en realidad un DataTable si se lo devuelve directamente quien deba manipular los datos deberá agregar validaciones que comprueben si esta o no el registro cargado.

Es por ello que estas validaciones se agrego del lado de los datos, en el if se pregunta si al menos hay un registro cargado, luego se toma el primero de la colección para retornarlo, en caso de no haber ninguno registro para los filtros asignados se devuelve null.

Al retornar el valor se castea a un tipo de dato algo particular “dtoContacto.ContactoRow”, esta es una clase que crea internamente el DataSet Tipado, y representa un registro del DataTable “Contacto” 

 

Cadena de Conexión


Seguramente se habrá notado en el código que al hacer uso del objeto SqlConnection se utiliza una clase que devuelve la cadena de conexión:

ConfigurationManager.ConnectionStrings["default"]

El ConfigurationManager permite el acceso al archivo de configuración situado en el “app.config”, este archivo al editarlo posee un formato xml en donde se podrá especificar la configuración del sistema, en este caso en particular se utiliza para especificar la cadena de conexión a la base de datos, pero podría servir para conservar otro tipo de datos variables para el sistema.

Lo bueno de esta implementación es que al compilar la aplicación el archivo de configuración queda libre como archivo de texto que podrá editarse con el notepad y cambiarse sin necesidad de recompilar la aplicación desarrollada. Esto es muy bueno para realizar cambios una vez que se ha realizado el deploy en la pc del usuario.

Para utilizar el ConfigurationManager es necesario agregar la referencia a la assembly de nombre “System.Configuration”

 

Consideraciones acerca de la aplicación de ejemplo


Los ejemplos de código están usando Sql Server como parte de la solución, por lo tanto se aconseja que localmente al menos se tenga instado el Sql Server 2008 Express con el servicio ejecutándose.

Para editar un item de la grilla una vez que este cargada, se deberá hacer click con el botón derecho del mouse sobre de la grilla, y seleccionar con que operación recuperar los datos. Se esta haciendo uso control ContextMenuStrip para la edición del registro seleccionado.

 

[C#] 
[VB.NET] 

27 comentarios:

  1. Hola Leandro soy nuevo en POO y tu página me ayuda mucho.

    El en método que se encapsula para ser reutilizado LoadContacto(reader),
    Ya tiene definidas las propiedades y su correspondiente registro que se está leyendo.

    Mi duda es: Si en otro formulario tengo que hacer una operación similar (traer registros a un Grid)
    Pero con solo un par de campos, ¿cómo puedo reutilizar el método si ya tiene las propiedades y su registro ya definidos?, ó ¿debo crear otra entidad y método similar?

    ResponderEliminar
  2. hola Armandiux

    en realidad en ese caso no returilizas creas uno nuevo para definir ese otro grupo de propiedades

    se podria si te animas a crear una suerte de doble metodo, uno que cargue un conjunto de propiedades y otro que complete el resto, pero quizas es para problemas
    Podrias desde un metodo de load cargar algunas propiedades y luego continuarlo en otro, cosa que si necesites poder invocar solo al segundo unicamente, pero me parece que haria mas compleja la situacion

    saludos

    ResponderEliminar
  3. Hola Leandro, tengo una inquietud, pero antes deseo felicidades por esos temas y ejemplos tan detallados que nos brindas. Es dificil conseguir informacion tan detallada como la que nos brindas.

    Mi inquietud es la siguiente:
    Tengo un DataGridView enlazado a una base de datos y deseo hacer consultas dinamicas es decir:

    - Tengo en mi grilla la relacion de pedidos. Deseo filtrar por: Categoria_producto, cliente, producto, fecha, y varios campos mas.
    - El usuario filtra por un rango de fechas y el resultado se muestra en la grilla.
    - Al resultado de este filtro(por fecha) el usuario elige filtrar ahora por categoria_productos y se muestra un nuevo resultado filtrado.
    - A este nuevo resultado (por fecha y categoria_producto) se hacer otros filtros elegidos por el usuario en cualquier orden, cua sea.

    Agradesco tu ayuda.

    Muchas gracias.

    ResponderEliminar
  4. hola

    o sea apuntas a algo como esto

    Filtros Condicionales (1/2)

    en donde puedas definir filtros segun se necesiten

    saludos

    ResponderEliminar
  5. Hola Leandro, estoy tratando de hacer lo mismo pero con menos columnas.. quisiera realizar una búsqueda pero no me devuelve nada el datagridview, no se donde puede estar el error. te dejo el código a ver si me podes ayudar

    Public Shared Function BuscarPorNombre(ByVal nombre As String) As ContactoEntity


    Dim product As ContactoEntity = Nothing
    Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("default").ToString())

    Dim sql As String = "Select [id]" & _
    ",[Nombre]" & _
    ",[Apellido]" & _
    ",[Edad]" & _
    "From Socios " & _
    "WHERE nombre LIKE '%@nombre%'"

    Dim cmd As New SqlCommand(Sql, conn)
    cmd.Parameters.AddWithValue("@nombre", nombre)

    conn.Open()

    Dim reader As SqlDataReader = cmd.ExecuteReader
    If reader.Read Then
    product = LoadContacto(reader)
    End If

    Return product
    End Using
    End Function

    No se si se va a entender,, Gracias. Utilice la misma sintaxis que utilizas vos.

    ResponderEliminar
  6. hola Mauro

    se respondio en el foro

    http://social.msdn.microsoft.com/Forums/es-ES/vbes/thread/e2550087-2178-4e83-95f9-0bf64806afb5

    saludos

    ResponderEliminar
  7. Hola Leandro, estoy haciendo una aplicación en capas en c#, en la que tengo en la capa de entidad una clase ClienteBE con los atributos dni,apellido1,apellido2,nombre,direccion,telefono, y 18 atributos mas, luego en la capa de acceso a datos tengo ClienteDAL con este metodo en la que utilizo un storeprocedure con solo los campos que quiero mostrar y devuelve una lista, en la que quiero solo recuperar los atributos dni,apellido1,apellido2,nombre,direccion,telefono solo estos, y mostrarlo en un datagridview de un winform el problema es que me muestra los atributos que quiero pero ademas los encabezados de los 18 atributos que defini en la clase , cuando elimino los demas atributos si me sale correctamente, pero yo voy a necesitar los demas atributos para hacer otras operaciones (insertar, actualizar) Mi pregunta es como haria para que me devuelva solo los campos que quiero sin los demas definidos en la clase, o tengo que crear una clase con solo los atributos que quiero mostrar? , ademas cuando hice este mismo metodo con un sqldataadapter y dataset y me devolvia un datatable si me funciono y salian las columnas que yo queria?, ahora debo hacerlo con sqldatareader y devolviendo una lista, espero que me haya entendido y me pueda ayudar, cualquier ayuda o sugerencia sera bien agradecida, este es el codigo

    public List ListarClientes()
    {
    SqlCommand cmd = new SqlCommand("usp_ListarCliente", cnx);
    cmd.CommandType = CommandType.StoredProcedure;
    try
    {
    cnx.Open();
    SqlDataReader lector = cmd.ExecuteReader(CommandBehavior.SingleResult);

    List lista = new List();

    if (lector.HasRows)
    {
    int indiceDNI = lector.GetOrdinal("dni");
    int indiceApellido1 = lector.GetOrdinal("Apellido1");
    int indiceApellido2 = lector.GetOrdinal("Apellido2");
    int indiceNombre = lector.GetOrdinal("Nombre");
    int indiceDireccion = lector.GetOrdinal("Direccion");
    int indiceTelefono1 = lector.GetOrdinal("Telefono1");

    while (lector.Read())
    {
    ClienteBE cliente = new ClienteBE();
    cliente.Dni = lector.GetString(indiceDNI);
    cliente.Apellido1 = lector.GetString(indiceApellido1);
    cliente.Apellido2 = lector.GetString(indiceApellido2);
    cliente.Nombre = lector.GetString(indiceNombre);
    cliente.Direccion = lector.GetString(indiceDireccion);
    cliente.Telefono1 = lector.GetString(indiceTelefono1);
    lista.Add(cliente);
    }
    }

    cnx.Close();
    return lista;
    }
    catch (Exception ex)
    {
    throw new Exception(ex.Message);
    }
    }

    ResponderEliminar
  8. Hola Leandro. Gracias por compartir el ejemplo. Te queria hacer una consulta. Como puedo hacer para usar un SqlDataReader con objetos cuando hago una consulta con InnerJoin ?
    Tengo que hacer lo mismo pero con los 2 objetos y en el while.reader() tengo que llenar 2 listas diferentes?
    Tendrías algun ejemplo a mano? Gracias

    ResponderEliminar
  9. hola

    analiza el codigo de este articulo

    n-Layer - SchoolManager - Herencia y navegación de entidades relacionadas

    alli explico como por medio de linq podrias agrupar los datos para cargar la entidad y sus relaciones basandote en una query que usa inner join

    saludos

    ResponderEliminar
  10. Hola Leandro. En la Facultad no aprendimos nada de Linq por lo cual no nos permiten usarlo. Solo es la única forma? Lo que hago siempre es crear un dataAdapter y un DataTable y llenar con el DataTable con la consulta mediante el DataAdapter, pero creo que ahí estoy trabajando en modo desconectado y debemos trabajar con el conectado. Perdón, pero son limitaciones a las cuales me tengo que adaptar..

    ResponderEliminar
  11. hola

    si tienes que hacerlo con un datareader lo mas simple va a ser crear dos queries separadas para cargar la entidad

    una query crea la entidad padre y luego lanzas otra que cargaria la lista relacionada

    o sea no lo hagas con un inner join, porque despues no podras recorrerlo para volcarlo a las entidades

    saludos

    ResponderEliminar
  12. ¡Excelente artículo, amigo Leandro!

    Información que es útil actualmente, y me sacó de muchas dudas, basado en tu experiencia para compartir las buenas prácticas.

    Agradecido por tomarte tu tiempo en la publicación del mismo.

    Recibe un cordial saludo.

    ResponderEliminar
  13. Hola que la consulta este en el sql?, y no en el visual

    ResponderEliminar
  14. hola CESAR

    te refieres a ejecutar un stored procedure?

    desde ado.net puedes hacerlo, solo indicas el nombre en el SqlCommand y asignas la propeidad CommandType

    saludos

    ResponderEliminar
  15. Hola Leandro,

    Los enlaces del proyecto no funcionan, me interesa revisar todo el código, te agradecería puedas resolver el inconveniente.

    gracias de antemano.

    ResponderEliminar
  16. Hola Leandro,

    Gracias por corregir los enlaces del proyecto, podrías también hacerlo para la parte 2(Recuperar Información MS Access), parte 3(Actualización Información Sql Server) y parte 4(Actualización Información Ms Access)

    gracias nuevamente...

    ResponderEliminar
  17. Hola Leandro, antes que todo muy buenos aportes sobre los temas, mi consulta es referido a la posibilidad de usar las cadenas de conexión en visual por ejemplo en mi caso es esta
    -------------------------------------
    Dim cnsql As New System.Data.SqlClient.SqlConnection("Data Source=Enzo-PC\SQLEXPRESS;Initial Catalog=Gym;Integrated Security=True")
    -------------------------------------
    que cada vez que hago algún tipo de consulta, inserción o modificación de datos usando esa cadena de conexión tengo que escribirla, yo quiero saber si se puede hacer que en vez de usarlo cada vez que lo necesite, unicamente invoque a un archivo .txt por ejemplo, que contenga esa cadena de conexión, y lo uso de manera global o solamente cambiando el nombre de la base de datos que se encuentra en ese .txt si quiero hacer uso de otra base de datos por decir asi otro ejemplo... desde ya muchas gracias y si no entiendes mi problema consultame porfavor..

    ResponderEliminar
  18. hola Enzo

    deberias definie la conexion en el archivo de configuracion .config usando el ConfigurationManager podrias tomar la conexion

    Archivos de Configuración - Una introducción (1/3)

    analiza la seccion "1- Agregar un archivo de configuración a nuestro proyecto"

    saludos

    ResponderEliminar
  19. Gracias Leandro, lo estoy viendo pero como soy un poco nuevo en esto lo estoy intentando ablandar, como veo la explicación está en c++ creo y mi proyecto es en VB hasta la parte de importar System.Configuration lo capto pero a la hora de crear mi clase de sección propias no capto el código que tendría que ir ahí con todo lo que continua...

    ResponderEliminar
  20. hola Enzo

    el ejemplo esta en c#, al final del articulo puedes descargar el ejemplo en vb.net

    no tienes que crear ninguna clase de conexion propia, usas la seccion de <connectionStrings> y tomas los datos por medio del ConfigurationManager

    saludos

    ResponderEliminar
  21. Leandro, un saludo fraternal.

    Estoy leyendo los datos de mi base de datos para llevarlos a los textbox del formulario, es un proyecto windows C#, pero al tratar de asignar una fecha que puede ser nula o no al textbox me genera error.

    Leo los datos de la base de datos mediante un método:

    if (consulta.Read())
    {
    if (consulta.HasRows)
    {
    vRes.IdCliente = Convert.ToInt32(consulta["IdCliente_Cl"]);
    vRes.Documento = Convert.ToString(consulta["Documento_Cl"]);
    vRes.Nombres = Convert.ToString(consulta["Nombres_Cl"]);
    vRes.Apellidos = Convert.ToString(consulta["Apellidos_Cl"]);
    vRes.Direccion = Convert.ToString(consulta["Direccion_Cl"]);
    vRes.Telefono = Convert.ToString(consulta["Telefono_Cl"]);
    vRes.Celular = Convert.ToString(consulta["Celular_Cl"]);
    vRes.Email = Convert.ToString(consulta["Email_Cl"]);
    vRes.FechaRegistro = Convert.ToDateTime(consulta["FechaRegistro_Cl"]);

    }
    }
    consulta.Close();
    consulta.Dispose();
    }

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

    private void txtIdCliente_KeyPress(object sender, KeyPressEventArgs e)
    {
    if (e.KeyChar == (char)Keys.Return)
    {
    int IdCliente = Convert.ToInt32(txtIdCliente.Text);
    try
    {
    oCli_Ent = oCli.ObtenerCliente(IdCliente);

    txtIdCliente.Text = oCli_Ent.IdCliente.ToString();
    txtDocumento.Text = oCli_Ent.Documento;
    txtNombres.Text = oCli_Ent.Nombres;
    txtApellidos.Text = oCli_Ent.Apellidos;
    txtDireccion.Text = oCli_Ent.Direccion;
    txtTelefono.Text = oCli_Ent.Telefono;
    txtCelular.Text = oCli_Ent.Celular;
    txtEmail.Text = oCli_Ent.Email;
    txtFechaIngreso.Text = oCli_Ent.FechaRegistro.ToString();
    }
    catch (Exception ex)
    {

    MessageBox.Show("Error" + ex.Message);
    }
    }
    }




    oCli_Ent = oCli.ObtenerCliente(IdCliente);

    txtIdCliente.Text = oCli_Ent.IdCliente.ToString();
    txtDocumento.Text = oCli_Ent.Documento;
    txtNombres.Text = oCli_Ent.Nombres;
    txtApellidos.Text = oCli_Ent.Apellidos;
    txtDireccion.Text = oCli_Ent.Direccion;
    txtTelefono.Text = oCli_Ent.Telefono;
    txtCelular.Text = oCli_Ent.Celular;
    txtEmail.Text = oCli_Ent.Email;
    txtFechaIngreso.Text = oCli_Ent.FechaRegistro.ToString();

    ResponderEliminar
    Respuestas
    1. hola
      Pero cual es el error por el cual falla ? quizas sea porque no es una fecha valida lo que intentas convertir a datetime
      Podrias ver de usar el DateTime.TrayParse() para convertir y si hay una fecha no valida no la convertira, pero no fallara
      saludos

      Eliminar
  22. Hola Leandro, primero que todo agradecerte el tiempo que te das por ayudar con tus buenos aportes.
    Lo segundo es que tengo una duda con el siguiente caso:

    Tengo una lista de tipo InformeX, la cual estoy llenando en la capa de datos por intermedio de sqlDataReader, pero tengo un dato que viene de la tabla, que es de tipo smallint , el cual es un codigo que dependiendo del numero debo pasar a un string (Ej : 1 = valido, 2 = no valido, 3= inexistente).

    La duda es si debo cambiar el tipo de dato en la estructura y declararlo como un string y asi convertirlo en la misma capa de datos.

    O debo dejarlo como int16 y cargarlo en la lista tal cual viene, y luego en la capa de negocio hacer esa regla y cargarlo en en una variable de clase???

    Espero haberme explicado bien.

    Saludos, muchas gracias.


    ResponderEliminar
    Respuestas
    1. hola
      Entiendo que este InformeX es una clase, si es asi podrias exponer una propiedad que aplique esta logica, algo como ser

      public class InformeX{

      public short Codigo {get;set;}

      public string CodDescripcion{

      switch(this.Codigo){
      case 1:
      return "valido";
      case 2:
      return "no valido";
      case 3:
      return "inexistente";
      }
      }
      }

      como veras en la tabla dejas el valor numerico, pero en la clase expones otra propiedad readonly para obtener la descripcion en base al codigo

      saludos

      Eliminar
  23. hola que tal, buen tuto podrias compartirme los archivos al parecer no estan disponibles

    ResponderEliminar
  24. Buenas tardes, la explicación es muy buena; pero me gustaría saber como hacer para actualizar por ejemplo la fila con nombre = "aaaa" con la condición de que si es el mismo registro lo actualice, pero si es otro nombre primero que me valide si existe para que no se repitan los datos del campo nombre. De antemano muchas gracias.

    ResponderEliminar
  25. encontré este video y me funcionó de maravilla y permite descargar el codigo: https://www.youtube.com/watch?v=0A1gq-erBxI espero les sirva

    ResponderEliminar