private string Grabar(string sIdEstructura, string sDenominacion, string sObligatorio, string strDatos)
    {
        string         sResul = "", sValoresInsertados = "";
        SqlConnection  oConn = null;
        SqlTransaction tr;

        #region abrir conexión y transacción
        try
        {
            oConn = Conexion.Abrir();
            tr    = Conexion.AbrirTransaccionSerializable(oConn);
        }
        catch (Exception ex)
        {
            if (oConn.State == ConnectionState.Open)
            {
                Conexion.Cerrar(oConn);
            }
            sResul = "Error@#@" + Errores.mostrarError("Error al abrir la conexión", ex);
            return(sResul);
        }
        #endregion
        try
        {
            //Datos básicos
            switch (nNivel)
            {
            case "0":
                NODO.Update(tr,
                            int.Parse(sIdEstructura),
                            Utilidades.unescape(sDenominacion),
                            (sObligatorio == "1") ? true : false
                            );
                break;

            case "1":
                SUPERNODO1.Update(tr,
                                  int.Parse(sIdEstructura),
                                  Utilidades.unescape(sDenominacion),
                                  (sObligatorio == "1") ? true : false
                                  );
                break;

            case "2":
                SUPERNODO2.Update(tr,
                                  int.Parse(sIdEstructura),
                                  Utilidades.unescape(sDenominacion),
                                  (sObligatorio == "1") ? true : false
                                  );
                break;

            case "3":
                SUPERNODO3.Update(tr,
                                  int.Parse(sIdEstructura),
                                  Utilidades.unescape(sDenominacion),
                                  (sObligatorio == "1") ? true : false
                                  );
                break;

            case "4":
                SUPERNODO4.Update(tr,
                                  int.Parse(sIdEstructura),
                                  Utilidades.unescape(sDenominacion),
                                  (sObligatorio == "1") ? true : false
                                  );
                break;
            }

            cargarEstructura();

            #region Estructura
            string[] aDatos = Regex.Split(strDatos, "///");

            foreach (string oEstructura in aDatos)
            {
                if (oEstructura == "")
                {
                    continue;
                }
                string[] aEstructura = Regex.Split(oEstructura, "##");
                ///aEstructura[0] = Opcion BD. "I", "U", "D"
                ///aEstructura[1] = ID Estructura
                ///aEstructura[2] = Orden

                switch (aEstructura[0])
                {
                case "U":
                    switch (nNivel)
                    {
                    case "0":
                        CDP.UpdateSimple(tr, int.Parse(aEstructura[1]), byte.Parse(aEstructura[2]));
                        break;

                    case "1":
                        CSN1P.UpdateSimple(tr, int.Parse(aEstructura[1]), byte.Parse(aEstructura[2]));
                        break;

                    case "2":
                        CSN2P.UpdateSimple(tr, int.Parse(aEstructura[1]), byte.Parse(aEstructura[2]));
                        break;

                    case "3":
                        CSN3P.UpdateSimple(tr, int.Parse(aEstructura[1]), byte.Parse(aEstructura[2]));
                        break;

                    case "4":
                        CSN4P.UpdateSimple(tr, int.Parse(aEstructura[1]), byte.Parse(aEstructura[2]));
                        break;
                    }
                    break;

                case "D":
                    switch (nNivel)
                    {
                    case "0":
                        CDP.Delete(tr, int.Parse(aEstructura[1]));
                        break;

                    case "1":
                        CSN1P.Delete(tr, int.Parse(aEstructura[1]));
                        break;

                    case "2":
                        CSN2P.Delete(tr, int.Parse(aEstructura[1]));
                        break;

                    case "3":
                        CSN3P.Delete(tr, int.Parse(aEstructura[1]));
                        break;

                    case "4":
                        CSN4P.Delete(tr, int.Parse(aEstructura[1]));
                        break;
                    }
                    break;
                }
            }
            #endregion

            Conexion.CommitTransaccion(tr);

            sResul = "OK@#@" + sValoresInsertados;
        }
        catch (Exception ex)
        {
            Conexion.CerrarTransaccion(tr);

            if (Errores.EsErrorIntegridad(ex))
            {
                sResul = "Error@#@Operación rechazada.\n\n" + Errores.mostrarError("Error al grabar los valores", ex, false);                                //ex.Message;
            }
            else
            {
                sResul = "Error@#@" + Errores.mostrarError("Error al grabar los valores", ex, false);
            }
        }
        finally
        {
            Conexion.Cerrar(oConn);
        }
        return(sResul);
    }