none
como usar executescalar arquitectura 3 Capas RRS feed

  • Pregunta

  • CAPA DATOS - Tengo dos clases CLASE_PARAMETRO Y CLASE_MANEJADOR 

    namespace CAPA_DATOS
    {
        public class CLASE_PARAMETROS
        {
            //Parametros
            public string Nombre { get; set; }
            public object valor { get; set; }
            public SqlDbType TipoDato { get; set; }
            public Int32 Tamano { get; set; }
            public ParameterDirection Direccion { get; set; }
    
            //Contructores
            //Entrada
            public CLASE_PARAMETROS(string objnombre, object objvalor)
            {
                Nombre = objnombre;
                valor = objvalor;
                Direccion = ParameterDirection.Input;
            }
            //Salida
            public CLASE_PARAMETROS(string objnombre, SqlDbType objTipoDato, Int32 ObjTamano)
            {
                Nombre = objnombre;
                TipoDato = objTipoDato;
                Tamano = ObjTamano;
                Direccion = ParameterDirection.Output;
            }
    
            
        }
    }
    
    namespace CAPA_DATOS
    {
        public class CLASE_MANEJADOR
        {
           public SqlConnection conexion = new SqlConnection(ConfigurationManager.ConnectionStrings["cadenaconexion"].ConnectionString);
            //Metodo Apertura
            void Abrir_Conexion()
            {
                if (conexion.State == ConnectionState.Closed)
                    conexion.Open();
            }
    
            void cerrar_conexion()
            {
                if (conexion.State == ConnectionState.Open)
                    conexion.Close();
    
            }
    
            //metodo ejecuta store procedure insert-delete-update
            public void ejecutar_sp(string NombreSP, List<CLASE_PARAMETROS> lst)
            {
                SqlCommand cmd;
                try
                {
                    Abrir_Conexion();
                    cmd = new SqlCommand(NombreSP, conexion);
                    cmd.CommandType = CommandType.StoredProcedure;
    
                    if (lst != null)
                    {
                        for (int i = 0; i <lst.Count; i++)
                        {
                            if (lst[i].Direccion == ParameterDirection.Input)
                            {
                                cmd.Parameters.AddWithValue(lst[i].Nombre, lst[i].valor);
                            }
                            if (lst[i].Direccion == ParameterDirection.Output)
                                cmd.Parameters.Add(lst[i].Nombre, lst[i].TipoDato, lst[i].Tamano).Direction = ParameterDirection.Output;
                        }
                    }
                    cmd.ExecuteNonQuery();
    
                    for (int i = 0; i< lst.Count; i++)
                    {
                        if (cmd.Parameters[i].Direction == ParameterDirection.Output)
                            lst[i].valor = cmd.Parameters[i].Value.ToString();
                    }
    
                }
                catch(Exception ex)
                {
                    throw ex;
                }
                cerrar_conexion();
    
            }
    
    
           //metodo para ejecutar consultas (select) o listados
            public DataTable listado(string NombreSP, List<CLASE_PARAMETROS> lst)
            {
                DataTable dt = new DataTable();
                SqlDataAdapter da;
    
                try
                {
                    da = new SqlDataAdapter(NombreSP, conexion);
                    da.SelectCommand.CommandType = CommandType.StoredProcedure;
                    if( lst != null)
                    {
                        for (int i = 0; i < lst.Count; i++)
                        {
                            da.SelectCommand.Parameters.AddWithValue(lst[i].Nombre, lst[i].valor);
                        }
                    }
                    da.Fill(dt);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return dt;
            }
    
    

    CAPA NEGOCIOS - CLASE_REGISTRO_VISITANTES

    namespace CAPA_NEGOCIOS
    {
        public class CLASE_REGISTRO_VISITANTES
        {
            public string _Num_Estudiante;
            public string _Fecha_Hora;
            public string _Ini_Estudiante;
            public DateTime _Fecha_Orientacion;
            public string _Apellido_Paterno;
            public string _Apellido_Materno;
            public string _Nombre;
                
    
            CLASE_MANEJADOR M = new CLASE_MANEJADOR(); //Referencia a la CLASE MANEJADOR
    
            //Registrar Estudiantes
            public string Registrar_Estudiante()
            {
                string msj = "";
                List<CLASE_PARAMETROS> lst = new List<CLASE_PARAMETROS>();
                try
                {
                    // Pasamos los parametros
                    lst.Add(new CLASE_PARAMETROS("@Num_Estudiante", _Num_Estudiante));
                    lst.Add(new CLASE_PARAMETROS("@Fecha_Hora", _Fecha_Hora));
                    lst.Add(new CLASE_PARAMETROS("@Ini_Estudiante", _Ini_Estudiante));
                    lst.Add(new CLASE_PARAMETROS("@Fecha_Orientacion", _Fecha_Orientacion));
                    lst.Add(new CLASE_PARAMETROS("@Apellido_Paterno", _Apellido_Paterno));
                    lst.Add(new CLASE_PARAMETROS("@Apellido_Materno", _Apellido_Materno));
                    lst.Add(new CLASE_PARAMETROS("@Nombre", _Nombre));
                                    
              
                    // pasamos parametro de salida
                    lst.Add(new CLASE_PARAMETROS("@Mensaje", SqlDbType.VarChar, 100));
                    M.ejecutar_sp("SP_INSERTAR_ESTUDIANTE", lst );
                    msj = lst[26].valor.ToString();
        }           catch (Exception ex)
                {
                    throw ex;
                }
                return msj;
            }
    
            public DataTable Buscar_Estudiante(string objini)
            {
                DataTable dt = new DataTable();
                List<CLASE_PARAMETROS> lst = new List<CLASE_PARAMETROS>();
                try
                {
                    lst.Add(new CLASE_PARAMETROS("@Ini_Estudiante", objini));
                    dt = M.listado("SP_LISTADO_ESTUDIANTE_INI", lst);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                return dt;
            }
    
    
           
        }
    }

    Todo funciona bien, pero ahora tengo la siguiente consulta, que se llama SP_CONSULTA_NUM_ESTUDIANTE

    SELECT COALESCE(Max(Num_Visitante),0) + 1 FROM CONFIGURACION_SISTEMA_TABLA

    necesito tanto en la CLASE_MANEJADOR  de mi capa datos crear un generico que me trabaje con executeescalar por que necesito que m consulta vaya a mi tabla CONFIGURACION_SISTEMA_TABLA y vea en numero que esta ahi ejemplo sea un 2 y en la CAPA DE PRESENTACION en un textbox llamado txtnumestudiante cuando le de al boton nuevo me coloque en este caso el numero 3 por que fue y busco en la tabla y el ultimo numero que vio fue un dos entonces pone el tres, pero no se como puedo utilizar un execute scalar en mis clases para llamarlo desde la CAPA PRESENTACION, gracias

    martes, 26 de junio de 2018 18:24

Todas las respuestas

  • Su distribución de responsabilidades es incorrecta pues la capa de negocios tiene el conocimiento del nombre del procedimiento almacenado.  Eso es parte de la capa de datos.  ¿Qué pasa si quiere usted cambiar la capa de datos por otra, que sea web services?  Ya no habría nombres de procedimientos almacenados.  Entonces cambiar su capa de datos implicaría tener cambios extensivos en su capa de negocio, y por lo tanto es un síntoma claro que las capas no fueron separadas correctamente.

    Lo que uno hace es crear un repositorio con métodos.  Los métodos que devuelven registros devuelven colecciones de objetos (o DataTable en el peor de los casos), y los métodos que devuelven un único datos pues tienen algún método que devuelve int, o string, o bool, etc. y sería la capa de datos la que especifica el procedimiento almacenado a ejecutar, o el URL del servicio web, etc.

    public class AlgunRepositorio
    {
        public int TotalRegistros()
        {
            //Aquí se configura el procedimiento almacenado, se ejecuta
            //cmd.ExecuteScalar() o ExecuteNonQuery() con parámetros output,
            //y se devuelve el resultado como un int.
        }
    
        public DataTable ListarVentasDelDia(DateTime fecha)
        {
            //Aquí se pasa el dato de fecha a un parámetro, se ejecuta cmd.ExecuteReader()
            //o ya que es un DataTable lo que se devuelve, un SqlDataAdapter, etc.
    }

    Luego en la capa de negocio solamente se llama a la función del repositorio adecuado, sin tener la necesidad de conocer de nombres de objetos en base de datos.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    martes, 26 de junio de 2018 20:02
    Moderador
  • Amigo Web Jose, yo tengo en la CAPA DATOS  dos clases, 

    CLASE PARAMETROS

    Aqui creo los parametros generales de entrada y salida para cualquier procedimiento almacenado, hasta ahi creo que voy bien

    CLASE MANEJADOR

    Aqui creo la cadena de conexion y los metodos generales que me van a servir para ejecutar todos aquellos procesos en todas mis clases de la CAPA_NEGOCIOS no importa si es insertar, actualizar, borrar o buscar(select) asi que no entiendo por que esta mal esa parte, ahora bien 

    CAPA NEGOCIOS

    Esta es la capa que me conecta directamente con la Capa de presentacion (Formularios windows en mi caso) asi que creo que lo mas logico es que llame a los procedimientos almacenados que correspondan a cada formulario dependiendo la necesidad, como puedo hacer eso desde la CAPA DATOS si mi coneccion directa con la capa de presentacion viene de la CAPA NEGOCIOS.

    Si tuviera usted algun ejemplo concreto de un cruv en la forma que usted me lo plantea por que en realidad no logro ver la logica exacta de lo que me habla, gracias por su cooperacion y ayuda.....

    martes, 26 de junio de 2018 20:37
  • Pensé que había puesto un ejemplo claro:  Imagine que su fuente de datos es un servicio web y no una base de datos.  ¿Dónde y cuánto tiene usted que cambiar código para usar un servicio web actualmente?  Tiene que deshacerse de su capa de datos completa porque es toda para SQL Server, y además de eso, tiene que hacer cambios en la capa de negocio porque también asume que "la capa de datos" es SQL Server.  Esto va en contra de los principios de diseño por capas.  La idea es que una capa pueda reemplazarse sin tener que introducir cambios en otras capas.  Se supone que uno debe poder cambiar capas una por una, no de a 2 ni de a 3.  ¿Entiende esto que le estoy diciendo?

    Luego, lo de sus clases.  Parámetros.  Esos son para SQL Server.  Eso debería ser una implementación INTERNA de su capa de datos.  Su capa de presentación no debería tener conocimiento de eso.  ¿Procedimientos almacenados?  Igual.  También va en datos, no en negocios.

    La capa de negocios necesita una capa de datos totalmente simplista:  "Dígame qué puede hacer y qué necesita de mí".  Lo mínimo posible.  El qué puede hacer es todo método y propiedad pública del repositorio; qué necesita son los parámetros de los métodos.  En el ejemplo que le puse, el repositorio está diciendo "Yo puedo darle las ventas de cualquier día que necesite, solamente necesito que me diga cuál fecha."  Ya luego si es por procedimiento almacenado, por llamada a web service, o por lectura de archivos xml, ya eso no es problema de la capa de negocio.  La capa de datos verá cómo lo hace.  Crear objetos SqlParameter, saberse los nombres de procedimientos almacenados, etc, todo eso le "vale madre" a la capa de negocios.  Todo eso es el mecanismo de la capa de datos y no tiene ni siquiera por qué ser público.

    //Un repositorio de base de datos.
    public class RepositorioVentas
    {
        public DataTable VentasDelDia(DateTime fecha)
        {
            using (SqlConnection conn = new SqlConnection(...))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand("dbo.uspVentasDelDia", conn))
                {
                    cmd.CommandType = Algo.StoredProcedure; //Jaja no recuerdo el nombre del enum.
                    cmd.Parameters.Add("fechaABuscar", SqlDbType.DateTime2).Value = fecha;
                    SqlDbAdapter da = ...
                    DataTable dt = new DataTable();
                    da.Fill(dt)
                    return dt;
                }
            }
        }
    
        public int TotalVendidoDelDia(DateTime fecha)
        {
            using (SqlConnection...)
            {
                conn.Open();
                using (SqlCommand cmd...)
                {
                    ...
                    object v = cmd.ExecuteScalar();
                    return (int)v;
                }
            }
        }
    }

    ¿Ve la diferencia?  Los métodos solamente piden lo mínimo necesario.  Todos los detalles de operación de una base de datos están internos al repositorio.  Cero exposición de la implementación interna y de objetos internos como parámetros.


    Jose R. MCP
    My GIT Repositories | Mis Repositorios GIT

    martes, 26 de junio de 2018 21:00
    Moderador
  • hola

    Por el codigo que publicas debo decirte que estas bastante lejos de tenes 3 capas o algo parecido

    [N-Tier] – Desarrollo en capas - Ejemplo Facturacion - parte 3

    analiza el ejemplo del articulo, no digo que sea el mejor ejemplo pero podria darte una pista de la responsabilidad de cada capa

    partamos de la base que

    - no deberias usar datatable si piensas en capas

    - no deberias tener ningun metodo que se llame ejecutar_sp()

    - tiene que definir entidades que representen el dominio y no llamarlas CLASE_PARAMETROS

    bueno esto son solo algunos consejos

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    martes, 26 de junio de 2018 21:40