public List <T> ZMX_Guardar <T>(List <T> lista) where T : CLASE_BASE
        {
            try
            {
                if (cliente == null)
                {
                    throw new Exception("Es necesario abrir la conexión antes.");
                }
                //antes de guardar, se validan los datos con los validadores
                foreach (T obj in lista)
                {
                    ValidacionesPrevioEnvioBD.ValidaNullables <T>(obj);
                    ValidacionesPrevioEnvioBD.ValidaPrecisionNumerica <T>(obj);
                    ValidacionesPrevioEnvioBD.ValidaStrings <T>(obj);
                    ValidacionesPrevioEnvioBD.ValidaTieneLlavePrimariaCorrecta <T>(obj);
                }

                List <T> objetosTotales = new List <T>();
                List <T> objetosUpdate  = new List <T>();
                List <T> objetosInsert  = new List <T>();
                List <T> retorno        = new List <T>();
                foreach (T obj in lista)
                {
                    retorno.Add(ZMX_Guardar <T>(obj));

                    //////<NOTA>SE POSPONE FUNCIONALIDAD POR INVESTIGACION</NOTA>
                    //////if (((CLASE_BASE)obj).ULTIMA_ACT == 0)
                    //////{
                    //////    ////es un registro nuevo, por lo que se inserta como nuevo y de forma individual (por la generacion de los consecutivos)
                    //////    T ob = ZMX_Guardar<T>(obj);
                    //////    objetosInsert.Add(ob);
                    //////    objetosTotales.Add(ob);
                    //////}
                    //////else
                    //////{
                    //////    //es una modificacion, se actualiza las versiones
                    //////    //es un registro nuevo, por lo que se inserta como nuevo
                    //////    ((CLASE_BASE)obj).ULTIMA_ACT++;
                    //////    Concurrencia.ValidaVersionConcurrencia<T>(obj, cliente);
                    //////    ((CLASE_BASE)obj).USUREG = ZMX_Usuario;
                    //////    ((CLASE_BASE)obj).FECHA_MODIFICACION = DateTime.Now;
                    //////    ((CLASE_BASE)obj).ES_NUEVO = false;

                    //////    objetosUpdate.Add(obj);
                    //////    objetosTotales.Add(obj);
                    //////}
                }

                //guardamos el listado de objetos por lotes (solamente los update, los nuevos se insertan uno por uno
                //debido al consecutivo
                /// <NOTA> por investigación se pospone esta funcionalidad, por el momento solo se actualizaran de forma individual</NOTA>
                //////String instruccionSQL = "BEGIN\r\n @SQL END;";
                //////String instrucciones = "";
                //////Dictionary<String, Object> parametrosByteArrayTotales = new Dictionary<string, Object>();
                //////int indice = 0;
                //////foreach (T obj in objetosUpdate)
                //////{
                //////    //se verifica que si el objeto trae propiedades de byte[]
                //////    if (Estructura.ContienePropiedadesByteArray<T>())
                //////    {
                //////        Dictionary<String, Object> parametrosByteArray = Estructura.ObtenerDiccionarioPropiedadesByteArray<T>(obj);
                //////        String instruccion = mapeoUpdate.Convertir<T>(obj) + "; ";
                //////        foreach (String llave in parametrosByteArray.Keys)
                //////        {
                //////            //se hacen transformaciones de las llaves, para poder sustituir los parametros donde van correctamente.
                //////            String llaveNueva = llave + "_" + indice;
                //////            //se agrega la llave transformada al array general con su valor
                //////            parametrosByteArrayTotales.Add(llaveNueva, parametrosByteArray[llave]);
                //////            //se hace la transformacion del parametro en el query para que correspondan con la transformacion.
                //////            instruccion = instruccion.Replace(llave, llaveNueva);
                //////        }
                //////        //finalmente se concatena la instruccion
                //////        instrucciones += instruccion;
                //////        //se incrementa el indice en 1 para que este listo para el proximo objeto
                //////        indice++;
                //////    }
                //////    else
                //////    {
                //////        instrucciones += mapeoUpdate.Convertir<T>(obj) + "; \r\n";
                //////    }
                //////}
                //////if (objetosUpdate.Count > 0)
                //////{
                //////    //si hay objetos a actualizar, se ejecuta la instruccion
                //////    instruccionSQL = instruccionSQL.Replace("@SQL", instrucciones);
                //////    //se actualizan los objetos
                //////    cliente.EjecutarUpdate(instruccionSQL, parametrosByteArrayTotales);
                //////}
                ////////se vuelven a consultar los registros con los datos ya actualizados.
                //////String querysPorID = "SELECT * FROM " + Estructura.ObtenNombreTabla<T>() + " WHERE (@CONDICIONES)";
                //////String condiciones = "";
                //////foreach (T obj in objetosTotales)
                //////{
                //////    condiciones += "(" + Estructura.ObtenCondicionBusquedaWhere<T>(obj) + ") OR ";
                //////}
                //////condiciones = condiciones.Substring(0, condiciones.Length - 4);
                //////querysPorID = querysPorID.Replace("@CONDICIONES", condiciones);
                //////DataTable dt = cliente.EjecutarSelect(querysPorID);
                //////lista = mapeoSelect.ConvertirAListaObjeto<T>(dt);
                return(lista);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public T ZMX_Guardar <T>(T obj) where T : CLASE_BASE
        {
            try
            {
                //antes de guardar, se validan los datos con los validadores
                ValidacionesPrevioEnvioBD.ValidaNullables <T>(obj);
                ValidacionesPrevioEnvioBD.ValidaPrecisionNumerica <T>(obj);
                ValidacionesPrevioEnvioBD.ValidaStrings <T>(obj);
                ValidacionesPrevioEnvioBD.ValidaTieneLlavePrimariaCorrecta <T>(obj);


                if (((CLASE_BASE)obj).ULTIMA_ACT == 0)
                {
                    //es un registro nuevo, por lo que se inserta como nuevo
                    ((CLASE_BASE)obj).ULTIMA_ACT         = 1;
                    ((CLASE_BASE)obj).USUARIO_CREACION   = ZMX_Usuario;
                    ((CLASE_BASE)obj).USUREG             = ZMX_Usuario;
                    ((CLASE_BASE)obj).FECHA_CREACION     = DateTime.Now;
                    ((CLASE_BASE)obj).FECHA_MODIFICACION = DateTime.Now;
                    //aqui debemos verificar si la clase tiene un id formado por formula y lo asignamos
                    CrearID <T>(obj);

                    String queryInsert = mapeoInsert.Convertir <T>(obj);

                    if (Estructura.ContienePropiedadesByteArray <T>())
                    {
                        Dictionary <String, Object> parametrosByteArray = Estructura.ObtenerDiccionarioPropiedadesByteArray <T>(obj);
                        int afectados = cliente.EjecutarInsert(queryInsert, parametrosByteArray);
                    }
                    else
                    {
                        int afectados = cliente.EjecutarInsert(queryInsert);
                    }

                    String    queryPorId = mapeoSelect.ObtenerQueryConsultaPorIdentificador <T>(obj);
                    DataTable dt         = cliente.EjecutarSelect(queryPorId);
                    obj = mapeoSelect.ConvertirAObjeto <T>(dt.Rows[0]);
                }
                else
                {
                    //es una modificacion, se actualiza las versiones
                    //es un registro nuevo, por lo que se inserta como nuevo
                    ((CLASE_BASE)obj).ULTIMA_ACT++;
                    Concurrencia.ValidaVersionConcurrencia <T>(obj, cliente);
                    ((CLASE_BASE)obj).USUREG             = ZMX_Usuario;
                    ((CLASE_BASE)obj).FECHA_MODIFICACION = DateTime.Now;
                    ((CLASE_BASE)obj).ES_NUEVO           = false;
                    //guardamos el objeto con un update
                    String queryUpdate = mapeoUpdate.Convertir <T>(obj);

                    if (Estructura.ContienePropiedadesByteArray <T>())
                    {
                        Dictionary <String, Object> parametrosByteArray = Estructura.ObtenerDiccionarioPropiedadesByteArray <T>(obj);
                        int afectados = cliente.EjecutarUpdate(queryUpdate, parametrosByteArray);
                    }
                    else
                    {
                        int afectados = cliente.EjecutarUpdate(queryUpdate);
                        if (afectados == 0)
                        {
                            throw new Exception("El objeto que se intenta guardar tuvo cambios en los valores que componen su identificación (Llave primaria, indices únicos, etc), por lo que no se pudo actualizar, favor de realizar la correción lógica necesaria. \n\nQuery update:\n\n" + queryUpdate + "\n\nPara guardar este objeto como uno nuevo, cambia el valor de ULTIMA_ACT a 0.");
                        }
                    }
                    String    queryPorId = mapeoSelect.ObtenerQueryConsultaPorIdentificador <T>(obj);
                    DataTable dt         = cliente.EjecutarSelect(queryPorId);
                    obj = mapeoSelect.ConvertirAObjeto <T>(dt.Rows[0]);
                }

                return(obj);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }