none
Problema con ALTER TABLE EN Access

    Pregunta

  • Hola a todos:

    Tengo una tabla Access 2007 a la cual precisaría cambiarle el tipo de campo Double por Decimal, y me está dando error indicándome el error: "Demasiados campos definidos", es una tabla que tiene 270 columnas pero el alter table lo estoy haciendo por trozos para que la carga de los mismos no sea muy grande, pero aún así mes está dando dicho error.

    la instrucción que estoy usando es la siguiente:

    Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
            Try
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    cnn.Open()
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf &
                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

    No sé si este tipo de cláusula ALTER TABLE se podría trabajar con una lista genérica, ya que lleva el alter column, el default, etc y no se si eso se podría hacer.

    Buenos, gracias a todos.

    Gemma

    sábado, 1 de octubre de 2016 16:39

Respuestas

  • "gemma_campillo" escribió:

    > Tengo una tabla Access 2007 a la cual precisaría cambiarle el tipo de campo
    > Double por Decimal, y me está dando error indicándome el error:
    > "Demasiados campos definidos",
    >
    > cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Gemma, la sintaxis de esa consulta es completamente válida, siempre y cuando la ejecutes desde fuera de la propia interfaz de usuario de Microsoft Access, es decir, que la ejecutes mediante la biblioteca de ADO o de ADO .NET, como tu la estás ejecutando, de hecho, me ha dado por ejecutarla y he modificado el tipo de dato de los 10 campos que aparecen en tu mensaje.

    Ignoro por completo de dónde puede venir el mensaje de error "Demasiados campos definidos". ¿?

    > No sé si este tipo de cláusula ALTER TABLE se podría trabajar con una
    > lista genérica, ya que lleva el alter column, el default, etc y no se
    > si eso se podría hacer.

    ¿Una lista genérica le va a pasar a la propiedad CommandText de un objeto OleDbCommand? Tendrás que ir pasándole elementos individuales de la lista, que para el caso es lo mismo que si le pasas 270 veces la sintaxis de la consulta ALTER TABLE que estás intentando ejecutar: una por cada campo que deseas modificar su tipo de dato.

    Revisa bien la sintaxis de las 270 consultas porque insisto que es correcta y yo no he tenido ningún problema. Ten en cuenta que parece ser que estás ejecutando todas las consultas dentro de un mismo bloque Try ... Catch, y si hay alguna cuya sintaxis está mal escrita, pues ahí es donde puede estar el problema. Punto de interrupción y pulsar 270 veces la tecla F8, o mejor, la tecla F10, para ejecutar de una sola vez las dos instrucciones que existen separadas por : en cada línea. :-))

    Por cierto, ¿270 campos tiene esa tabla llamada EFE? Si no me he equivocado al sumar, me salen 245, y el límite está en 255 campos. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    sábado, 1 de octubre de 2016 18:06
    Moderador
  • "gemma_campillo" escribió:

    > Tengo otras tablas con 70 columnas y con casi todos sus campos doubles (access)
    > y también me está dando problema, creo que hay una forma de hacerlo con "schemas"
    > pero no tengo ni idea, creo que lo puede hacer en un bloque sin tanta ida y venida
    > con la actualización de cada campo.

    No, porque entonces me hubiera dado a mí el mismo error, y afortunadamente no ha sido así.

    Que yo sepa, puedes ejecutar perfectamente el método ExecuteNonQuery (que se supone es al que llama el método ExecuteAction) varias veces, tal cual lo estás haciendo:

    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Pero como te he comentado en mi respuesta anterior, si alguno falla porque su sintaxis esté mal escrita, entonces pasará el control al bloque Catch que tienes insertado en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    ¿Has abierto la base con el propio Microsoft Access para ver si el tipo de dato de algunos campos se han modificado?

    Y en cuanto a los "schemas", no sé a qué esquemas te refieres. ¿?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo sábado, 1 de octubre de 2016 18:29
    sábado, 1 de octubre de 2016 18:15
    Moderador
  • "gemma_campillo" escribió:

    > Yo mientras ese error no sea porque hay muchos campos, ya estoy tranquila y
    > seguro que algo que he copiado o escrito mal.
    >
    > Es que hay otros procedimientos que tienen 80 campos a cambiar y va perfecto.

    Yo estoy porque se debe a que en alguna línea tienes mal escrita la sintaxis de la consulta ALTER TABLE.

    > YA verás que me has dado la luz y por ahí estará el error o errores.

    Pues te voy a dar un poco "más de luz". Como observo que por cada línea estás llamando al método MetodosData.ExecuteAction:

        cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    te comento que tampoco es necesario que SIEMPRE llames al método ExecuteAction, porque si éste método se encuentra implementado como te comenté en su día, en el mismo se estará abriendo la conexión y destruyéndola, por lo que no tiene sentido que si vas a ejecutar 240 consultas ALTER TABLE, estés abriendo, cerrando y destruyendo innecesariamente la conexión.

    Eso por un lado, y por otro, observo que también abres la conexión en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2:

        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
       
            Try

                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()

                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()

                    cnn.Open()  --> Abres la conexión

                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Si la conexión la abres en dicho procedimiento y también se intenta abrir en el método ExecuteAction, lo que estarás haciendo es provocar tu misma una excepción del tipo InvalidOperationException en el método ExecuteAction, con lo cual la ejecución del código pasará al bloque Catch que tienes en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    Entiendo que para estos casos particulares, mejor será que llames directamente al método ExecuteNonQuery del objeto DbCommand:

        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    
            ' Para contar el número de campos actualizados. Cuando
            ' esté el código depurado, eliminar la variable local.
    ' Dim n As Integer Try ' Declaramos una variable Connection Using cnn As DbConnection = da.CreateConnection() ' Si el método da.CreateConnection no le ha asignado la cadena ' de conexión al objeto DbConnection devuelto, tienes que ' asignársela aquí. ' ' cnn.ConnectionString = <cadena de conexión o indicar el método dónde se genera> ' Creamos el Commando Dim cmd As DbCommand = cnn.CreateCommand() ' Abrir la conexión cnn.Open() With cmd .CommandText = "ALTER TABLE EFE ALTER Column ResLegalEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResVoluntEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResEspecEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResEstatutEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() End With End Using Catch ex As Exception MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf & "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error) Finally ' Cuando el código esté totalmente depurado, eliminar el bloque Finally. MessageBox.Show("Nº de campos modificados: " & CStr(n)) End Try End Sub

    Fíjate bien en los comentarios que hago sobre la variable local llamada 'n' y sobre la cadena de conexión del objeto DbConnection devuelto por el método da.CreateConnection().

    La variable 'n' la he puesto para que mientras estés depurando el código obtengas el número de campos que se han modificado, aunque se haya producido una excepción. Obviamente, cuando todo esté depurado, tendrás que eliminar del procedimiento dicha variable 'n' y el bloque Finally.

    >    Catch ex As Exception
    >       MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf &
    >                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)

    Ignoro si el método CambiarTipoDatosAccessTabla_EFEParte2 va a formar parte del ejecutable final de tu programa o solamente lo estás ejecutando temporalmente mientras cambias los tipos de datos de los campos de la tabla.

    Si es lo primero, yo no puedo aceptar de ninguna manera que le muestres un mensaje al usuario donde se le indica que "Acepte para continuar" después de haberse producido un error, que yo calificaría de GRAVÍSIMO, ya que afecta a los tipos de datos de los campos, y por tanto, a la estructura de la tabla EFE o de cualquier otra.

    ¡Eso no se puede o no se debería hacer! Si se ha producido ese error en el método CambiarTipoDatosAccessTabla_EFEParte2 , en mi opinión personal es una verdadera barbaridad que le indiques al usuario que continúe como si no hubiera pasado nada. ¿No te das cuenta que esa tabla puede estar en un estado inconsistente, donde unos campos se han modificado su tipo de datos y otros no, por lo que posteriormente el usuario puede obtener resultados inesperados.

    Ante cualquier error de éste tipo que afecte a la estructura de la propia base de datos, entiendo que lo correcto es FINALIZAR EL PROGRAMA SIN MÁS, previa escritura en algún archivo tipo *.log del error que se ha producido, ya que los datos existentes en cualquier informe que genere el usuario, puede que no sean todo lo exactos que debieran. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    domingo, 2 de octubre de 2016 7:23
    Moderador
  • "gemma_campillo" escribió:

    > Voy a seguir probando ya que esa es la que generaba un error y ahora ya no lo hace,
    > he estado repasando los campos y están bien, aunque no acabo de entender por que
    > con tu procedimiento "MetodosDatos.ExecuteAction(cmd)" y manda error cuando siempre
    > va bien dicho procedimiento, si que es verdad que ahora es muy más rápido con executeNonQuery.

    El procedimiento MetodosDatos.ExecuteAction(cmd) siempre va bien, porque éste lo único que se limita es a configurar un objeto DbConnection apropiado y a ejecutar el método ExecuteNonQuery del objeto DbCommand especificado.

    Pero ten en cuenta que, como en dicho procedimiento también se configura un objeto Connection, con su correspondiente cadena de conexión, puede que ésta cadena de conexión sea DIFERENTE a aquella que tiene asignada el objeto Connection devuelto por el método da.CreateConnection() en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2().

    Es decir, en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2() se crea un objeto Connection, y en el método ExecuteAction() otro objeto Connection, que puede que tenga una cadena de conexión diferente que la que tiene el primer objeto Connection.

    Cuando ahora has dejado de llamar al método MetodosDatos.ExecuteAction es cuando ha funcionado todo, por lo que no me queda más que pensar que las cadenas de conexión de ambos objetos Connection sean diferentes: una configurada para Access (la del método CambiarTipoDatosAccessTabla_EFEParte2) y otra configurada para SQL Server o SQL Server Compact (la del método MetodosDatos.ExecuteAction), de ahí esos "mensajes de error extraños" del tipo "Demasiados campos definidos", que me suena más a un error de SQL Server que de Access. ;-)

    Si el problema se debía a esto, entiendo que NO DEBERÍAS CONFIGURAR un objeto Connection si posteriormente tienes pensado llamar al método MetodosDatos.ExecuteAction(), que se supone es el encargado de crear y configurar correctamente el objeto Connection que se va a utilizar para ejecutar una acción concreta.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo domingo, 2 de octubre de 2016 8:20
    domingo, 2 de octubre de 2016 8:02
    Moderador
  • "gemma_campillo" escribió:

    > Yo creo que las cadenas de conexión son las mismas, la establezco en el submain
    > al arrancar y ya después me funciona desde el app.Config para toda la aplicación,
    > de cualquier manera el o los dichosos errores me dan a pensar que voy a repasar
    > en cuanto acabe esto, los executeaction.cmd porque nunca me han dado errores de
    > nada pero si que te digo que la conexión en algunos lugares la abro dos veces,
    > una el Cnn.Open del procedimiento y otra claro ejecutando tu executeaction.cmd.

    ¿Seguro que la cadenas de conexión son iguales? ;-)

    La conexión la abres DOS VECES porque estás utilizando DOS OBJETOS CONNECTION DIFERENTES, porque si fuera el mismo objeto Connection, obtendrías una "preciosa" InvalidOperationException la segunda vez que intentas abrir la conexión, ya que deberías de saber que un objeto Connection que ya está abierto, NO SE PUEDE ABRIR de nuevo hasta que no se cierre.

    Y deberías de examinar bien si estás o no utilizando la misma cadena de conexión. De todas maneras, NO DEBERÍAS LLAMAR al método compartido ExecuteAction de la clase o módulo llamado MetodosDatos si previamente has configurado un objeto DataAccessInvariant o como se llame la clase que referencia el objeto llamado 'da':

        ' Declaramos una variable Connection
        Using cnn As DbConnection = da.CreateConnection()

    ¿La variable 'da' es del tipo DataAccessInvariant, una clase que en su día te recomendé para trabajar con diferentes proveedores de datos? Si es así, una vez que hayas obtenido un objeto DbConnection invariable del proveedor de datos, estás en disposición de obtener fácilmente el objeto DbCommmand:

            ' Creamos el comando
            Dim cmd As DbCommand = cnn.CreateCommand()

    Pues si ya tienes una conexión (cnn) y un comando (cmd), no es necesario, ni deberías hacerlo, llamar al método compartido ExecuteAction de la clase o módulo llamado MetodosDatos, porque tan solo tienes que llamar al método ExecuteNonQuery del objeto DbCommand creado:

            ' Abrir la conexión
            cnn.Open()

            ' Configurar la propiedad CommandText
            cmd.CommandText = "ALTER TABLE ..."

            ' Ejecutar el comando
            cmd.ExecuteNonQuery()

        End Using  ' Destruir la conexión

    El método compartido ExecuteAction de la clase o módulo MetodosDatos lo podrás utilizar cuando NO TENGAS UN OBJETO CONNECTION DECLARADO de antemano, es decir, solamente tienes un objeto Command perteneciente a un proveedor de datos concreto (OleDbCommand, SqlCommand, SqlCeCommand, etc):

        ' Configurar un objeto OleDbCommand
        Using cmd As New OleDbCommand()
        
            ' Configurar la propiedad CommandText
            cmd.CommandText = "ALTER TABLE ..."
    
            ' Ejecutar el comando
            MetodosDatos.ExecuteAction(cmd)
    
        End Using

    Y sería en el método ExecuteAction donde se utilizaría un objeto OleDbConnection para abrir la conexión, ejecutar el comando especificado, destruir la conexión y devolver el número de registros afectados si procede, aunque también habría que ver la implementación definitiva que estás utilizando del método ExecuteAction, porque han sido tantas veces la que he modificado su implementación para adaptarla a las necesidades de la gente, como puede haber sido tu caso, que ya no sé ni la versión que puede estar utilizando cada una de ellas.

    Fíjate la diferencia entre crear un comando de una u otra manera:

            ' Creamos un comando asociado a un objeto OleDbConnection previamente declarado
            Dim cmd As OleDbCommand = cnn.CreateCommand()

            ' Creamos un comando que NO ESTÁ asociado a ningún objeto OleDbConnection
           Dim cmd As New OleDbCommand()

    Los dos son objetos OleDbCommand válidos, pero mientras el primero ya conoce cuál es su objeto OleDbConnection, al segundo hay que añadírselo posteriormente a través de su propiedad Connection:

           ' Le asignamos el objeto Connection al objeto Command
           cmd.Connection = cnn

    Salvo que se utilice la siguiente sobrecarga del constructor de la clase OleDbCommand:

           Dim cmd As New OleDbCommand(<Consulta SQL>, cnn)

    Pero lo dicho: ¿tienes un objeto Connection invariable? Si la respuesta es afirmativa, crea un objeto Command mediante el método CreateCommand del objeto DbConnection, y ejecuta su método ExecuteNonQuery.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    domingo, 2 de octubre de 2016 9:34
    Moderador
  • "gemma_campillo" escribió:

    > Vale, y ahora pasa por la tira de registros que los tengo en
    > varios procedimientos y casca en este y siempre es la misma tabla EFE.

    Pues según la imagen que has publicado, no entiendo ya a qué se puede deber el error que obtienes, porque la cadena de conexión apunta a la base de datos de Access que se comprende está en la misma carpeta que el ejecutable de la aplicación.

    > Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    >
    >        Try
    >
    >            ' Declaramos una variable Connection
    >            Using cnn As DbConnection = da.CreateConnection()
    >

    ¿Dónde y cómo creas la instancia de la clase "da"? ¿La tienes declarada a nivel global? Te lo pregunto porque no observo que se encuentra declarada e instanciada en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    > le he puesto el bloque "finally" a todos para probar (después ya lo sacaré),
    > y todos los messagebox me indicas: registros modificados 0, claro es, por
    > que antes ya estaban modificados a decimal, por lo tanto funciona perfecto.

    La verdad es que el método ExecuteNonQuery devuelve 0 registros afectados (o -1, no recuerdo ahora mismo) cuando ejecuta una consulta de definición de datos, como es el caso de la consulta ALTER TABLE, así que de nada sirve el valor de la variable 'n' tal cual aparece en el ejemplo.

    Tendrías que sumar una unidad posteriormente a la ejecución del método ExecuteNonQuery:

        With cmd
            .CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
        End With
    


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo domingo, 2 de octubre de 2016 14:44
    domingo, 2 de octubre de 2016 12:03
    Moderador
  • "gemma_campillo" escribió:

    > La instancia la creo a nivel de módulo(form, clase.)
    >
    Public Shared Property da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)

    ¡Madre mía! ¿Tu sabes realmente lo que significa esa declaración?

    Estás compartiendo (Shared) una propiedad (Property) pública (Public) que puede ser leída (Get) y puede ser modificada (Set) desde cualquier parte de tu aplicación, y por si no fuera bastante, la estás implementando como una  propiedad autoimplementada automáticamente, por lo te será complicado acceder al campo privado que el compilador de Visual Basic habrá creado automáticamente para devolver y establecer el valor de dicha propiedad.

    Gemma, yo comprendo que es muy fácil trabajar con ese tipo de declaraciones, pero precisamente, en esa facilidad es donde se encuentra el peligro, porque por mucho que digas que funciona perfectamente, ¿puedes estar segura de que no se ha modificado sin querer el valor de la propiedad 'da' en alguna parte de tu proyecto sin que seas consciente de ello?

    Te he comentado antes, e insisto en ello, que el mensaje de error "Demasiados campos definidos", me suena más a SQL Server que a Access, y como te encuentras trabajando con 3 tipos de bases de datos diferentes, ¿no puedes pensar que el valor de la propiedad compartida 'da' se haya modificado y su cadena de conexión esté apuntando a una base de SQL Server?

    Por la imagen que has publicado anteriormente, ya sé que la cadena apunta a una base de Access, pero mejor será que coloques un punto de interrupción en una llamada cualquiera al método ExecuteNonQuery, y compruebes el valor que tiene la propiedad ConnectionString de la propiedad Connection del objeto DbCommand, es decir, en la Ventana Inmediato consulta el siguiente valor:

        ?cmd.Connection.ConnectionString

    y pulsa la tecla Enter para ver qué valor tiene actualmente la cadena de conexión del objeto Connection actual.

    Te comento que la clase DataAccessInvariant no consume recursos a la hora de crear una instancia de la misma, ni la clase abre conexiones que después haya que cerrar y destruir, por lo que en mi opinión personal no tiene ningún sentido que utilices una propiedad compartida de lectura y escritura para ahorrarte tener que declarar y crear una nueva instancia de la clase DataAccessInvariant cada vez que la vayas a utilizar. Es decir, que en lugar de mantener a nivel del proyecto la declaración que estás utilizando, mi opinión es que en cada método que vayas a hacer uso de la clase DataAccessInvariant crees una nueva instancia de ella:

        Public Sub NombreMetodo()
    
    ' Declarar y crear una nueva instancia de la clase DataAccessInvariant.
    Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion) Using cnn As DbConnection = da.CreateConnection() Dim cmd As DbCommand = cnn.CreateCommand() cmd.CommandText = "ALTER TABLE ..." cnn.Open() cmd.ExecuteNonQuery() End Using End Sub

    Esta es la manera de asegurarte que en ninguna otra parte de tu proyecto se ha modificado sin querer el valor que va a ser utilizado para la instancia de la clase DataAccessInvariant creada, lo que también es válido para otros tipos de objetos diferentes.

    > La he estado probando hace un ratito a nivel de método y es lo mismo, da el error.
    > Lo que si estoy viendo es que eso solo me está pasando con 2 tablas que contienen
    > más de 100 campos y no se si por ahí pueden venir los tiros, aunque cada executenonquery
    > la estemos haciendo campo por campo y no sea que si la tabla tiene muchos campos detecte
    > ese problema y proceda a emitir el error.

    Que yo sepa, no existe un número exacto de veces que puedes llamar al método ExecuteNonQuery; lo puedes llamar tantas veces como desees. Y en cuanto al número de campos de la tabla, mientras que no supere los 255 campos, no tienes por qué tener problemas.

    Dices que solamente te pasa con 2 tablas: EFE y TAM. Me ha dado por mirar si los nombres son palabras reservada de Access, y te digo que no lo son:

    Palabras y símbolos reservados de Access 2007

    Si has podido modificar el tipo de dato de los campos existentes en otras tablas diferentes utilizando la consulta

        ALTER TABLE [NombreTabla] ALTER COLUMN [NombreCampo] Decimal(18,2) DEFAULT 0

    entonces el problema no es de la sintaxis de la consulta ALTER TABLE, por lo que el problema tiene que estar en todo el proceso de actualizar los tipos de datos de los campos correspondientes a las tablas EFE y TAM.

    Para ver si eres capaz de modificar los tipos de datos de esas tabla, crea un nuevo proyecto de Visual Basic, e inserta en el formulario de inicio el siguiente procedimiento:

    Imports System.Data.OleDb
    
    Public Class Form1
    
        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    
            ' Para contar el número de campos actualizados. Cuando
            ' esté el código depurado, eliminar la variable local.
            '
            Dim n As Integer
    
            Try
                ' Declaramos una variable Connection
                Using cnn As New OleDbConnection(escribe aquí la cadena de conexión con la base de Access)
    
                    ' Creamos el Commando
                    Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                    ' Abrir la conexión
                    cnn.Open()
    
                    With cmd
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                    End With
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf &
                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
    
            Finally
                ' Cuando el código esté totalmente depurado, eliminar el bloque Finally.
                MessageBox.Show("Nº de campos modificados: " & CStr(n))
    
            End Try
    
        End Sub
    
    End Class

    Y desde el evento Click de cualquier control Button llama al método CambiarTipoDatosAccessTabla_EFEParte2.

    Esto es lo que exactamente hice ayer y no tuve ningún tipo de problema para asignar el tipo de dato Decimal a los 10 campos de la tabla EFE. Inténtalo, y si observas que se modifican, entonces el problema lo tienes en tu aplicación. ¿Dónde? ¡Ni idea! ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    domingo, 2 de octubre de 2016 16:25
    Moderador

Todas las respuestas

  • gemma_campillo,

    Sin conocer el tipo de proyecto que llevas, 270 columnas en una tabla me parece que es síntoma de que hay serios problemas en el modelamiento, son demasiadas columnas para una tabla y definitivamente eso impactaría contra el rendimiento (en caso se permita).

    Entiendo que una tabla en Ms-Access no permite contener mas de 255 columnasEspecificaciones de Access 2010 (aplica también para Ms Access 2007), el mensaje de error es claro en ello, quizá sea momento de normalizar la tabla.



    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    sábado, 1 de octubre de 2016 17:34
  • Hola Williams:

    No es ese el problema, aunque llevas razón. Tengo otras tablas con 70 columnas y con casi todos sus campos doubles (access) y también me está dando problema, creo que hay una forma de hacerlo con "schemas" pero no tengo ni idea, creo que lo puede hacer en un bloque sin tanta ida y venida con la actualización de cada campo.

    Muchas gracias como siempre.

    Gemma

    sábado, 1 de octubre de 2016 17:38
  • "gemma_campillo" escribió:

    > Tengo una tabla Access 2007 a la cual precisaría cambiarle el tipo de campo
    > Double por Decimal, y me está dando error indicándome el error:
    > "Demasiados campos definidos",
    >
    > cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Gemma, la sintaxis de esa consulta es completamente válida, siempre y cuando la ejecutes desde fuera de la propia interfaz de usuario de Microsoft Access, es decir, que la ejecutes mediante la biblioteca de ADO o de ADO .NET, como tu la estás ejecutando, de hecho, me ha dado por ejecutarla y he modificado el tipo de dato de los 10 campos que aparecen en tu mensaje.

    Ignoro por completo de dónde puede venir el mensaje de error "Demasiados campos definidos". ¿?

    > No sé si este tipo de cláusula ALTER TABLE se podría trabajar con una
    > lista genérica, ya que lleva el alter column, el default, etc y no se
    > si eso se podría hacer.

    ¿Una lista genérica le va a pasar a la propiedad CommandText de un objeto OleDbCommand? Tendrás que ir pasándole elementos individuales de la lista, que para el caso es lo mismo que si le pasas 270 veces la sintaxis de la consulta ALTER TABLE que estás intentando ejecutar: una por cada campo que deseas modificar su tipo de dato.

    Revisa bien la sintaxis de las 270 consultas porque insisto que es correcta y yo no he tenido ningún problema. Ten en cuenta que parece ser que estás ejecutando todas las consultas dentro de un mismo bloque Try ... Catch, y si hay alguna cuya sintaxis está mal escrita, pues ahí es donde puede estar el problema. Punto de interrupción y pulsar 270 veces la tecla F8, o mejor, la tecla F10, para ejecutar de una sola vez las dos instrucciones que existen separadas por : en cada línea. :-))

    Por cierto, ¿270 campos tiene esa tabla llamada EFE? Si no me he equivocado al sumar, me salen 245, y el límite está en 255 campos. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    sábado, 1 de octubre de 2016 18:06
    Moderador
  • "gemma_campillo" escribió:

    > Tengo otras tablas con 70 columnas y con casi todos sus campos doubles (access)
    > y también me está dando problema, creo que hay una forma de hacerlo con "schemas"
    > pero no tengo ni idea, creo que lo puede hacer en un bloque sin tanta ida y venida
    > con la actualización de cada campo.

    No, porque entonces me hubiera dado a mí el mismo error, y afortunadamente no ha sido así.

    Que yo sepa, puedes ejecutar perfectamente el método ExecuteNonQuery (que se supone es al que llama el método ExecuteAction) varias veces, tal cual lo estás haciendo:

    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)
    cmd.CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Pero como te he comentado en mi respuesta anterior, si alguno falla porque su sintaxis esté mal escrita, entonces pasará el control al bloque Catch que tienes insertado en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    ¿Has abierto la base con el propio Microsoft Access para ver si el tipo de dato de algunos campos se han modificado?

    Y en cuanto a los "schemas", no sé a qué esquemas te refieres. ¿?


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo sábado, 1 de octubre de 2016 18:29
    sábado, 1 de octubre de 2016 18:15
    Moderador
  • Hola Enrique:

    De acuerdo voy a repasar una por una y haber porque casca., a ver si el mensaje quiere decir que hay un error de sintaxis. Y si, has contado la tabla correctamente, lo he dicho por error, que eran 270 campos, porque había multiplicado los campos en bloques de 10 por 27, y ya veo que ahí puede haber un error.

    Bueno, como estoy ya acabada con este rollo, me voy un rato a ver la tele, que leches, que ya toca y mañana de madrugada me pongo con esto.

    Un fuerte abrazo y muchas gracias por la explicación.

    Gemma

    sábado, 1 de octubre de 2016 18:29
  • Hola Enrique:

    Que no había visto el segundo correo, y si, hay datos que han cambiado y y otros no, por ahí en el Access veré donde no ha habido cambio porque por ahí puede haber un error. Lo repasaré y a ver que pasa.

    Por otro lado, si pasa al bloque TryCatch que es cuando me dice el ex.Message que hay demasiados campos definidos. YA verás que me has dado la luz y por ahí estará el error o errores.

    Yo mientras ese error no sea porque hay muchos campos, ya estoy tranquila y seguro que algo que he copiado o escrito mal.

    Es que hay otros procedimientos que tienen 80 campos a cambiar y va perfecto.

    Ah, lo de los "schemas" yo tampoco se de que va, pero queda bonita esa palabreja. ja,ja.

    Un saludo.

    Gemma



    sábado, 1 de octubre de 2016 18:31
  • "gemma_campillo" escribió:

    > Yo mientras ese error no sea porque hay muchos campos, ya estoy tranquila y
    > seguro que algo que he copiado o escrito mal.
    >
    > Es que hay otros procedimientos que tienen 80 campos a cambiar y va perfecto.

    Yo estoy porque se debe a que en alguna línea tienes mal escrita la sintaxis de la consulta ALTER TABLE.

    > YA verás que me has dado la luz y por ahí estará el error o errores.

    Pues te voy a dar un poco "más de luz". Como observo que por cada línea estás llamando al método MetodosData.ExecuteAction:

        cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    te comento que tampoco es necesario que SIEMPRE llames al método ExecuteAction, porque si éste método se encuentra implementado como te comenté en su día, en el mismo se estará abriendo la conexión y destruyéndola, por lo que no tiene sentido que si vas a ejecutar 240 consultas ALTER TABLE, estés abriendo, cerrando y destruyendo innecesariamente la conexión.

    Eso por un lado, y por otro, observo que también abres la conexión en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2:

        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
       
            Try

                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()

                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()

                    cnn.Open()  --> Abres la conexión

                    cmd.CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : MetodosDatos.ExecuteAction(cmd)

    Si la conexión la abres en dicho procedimiento y también se intenta abrir en el método ExecuteAction, lo que estarás haciendo es provocar tu misma una excepción del tipo InvalidOperationException en el método ExecuteAction, con lo cual la ejecución del código pasará al bloque Catch que tienes en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    Entiendo que para estos casos particulares, mejor será que llames directamente al método ExecuteNonQuery del objeto DbCommand:

        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    
            ' Para contar el número de campos actualizados. Cuando
            ' esté el código depurado, eliminar la variable local.
    ' Dim n As Integer Try ' Declaramos una variable Connection Using cnn As DbConnection = da.CreateConnection() ' Si el método da.CreateConnection no le ha asignado la cadena ' de conexión al objeto DbConnection devuelto, tienes que ' asignársela aquí. ' ' cnn.ConnectionString = <cadena de conexión o indicar el método dónde se genera> ' Creamos el Commando Dim cmd As DbCommand = cnn.CreateCommand() ' Abrir la conexión cnn.Open() With cmd .CommandText = "ALTER TABLE EFE ALTER Column ResLegalEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResVoluntEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResEspecEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResEstatutEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() .CommandText = "ALTER TABLE EFE ALTER Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : n += .ExecuteNonQuery() End With End Using Catch ex As Exception MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf & "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error) Finally ' Cuando el código esté totalmente depurado, eliminar el bloque Finally. MessageBox.Show("Nº de campos modificados: " & CStr(n)) End Try End Sub

    Fíjate bien en los comentarios que hago sobre la variable local llamada 'n' y sobre la cadena de conexión del objeto DbConnection devuelto por el método da.CreateConnection().

    La variable 'n' la he puesto para que mientras estés depurando el código obtengas el número de campos que se han modificado, aunque se haya producido una excepción. Obviamente, cuando todo esté depurado, tendrás que eliminar del procedimiento dicha variable 'n' y el bloque Finally.

    >    Catch ex As Exception
    >       MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf &
    >                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)

    Ignoro si el método CambiarTipoDatosAccessTabla_EFEParte2 va a formar parte del ejecutable final de tu programa o solamente lo estás ejecutando temporalmente mientras cambias los tipos de datos de los campos de la tabla.

    Si es lo primero, yo no puedo aceptar de ninguna manera que le muestres un mensaje al usuario donde se le indica que "Acepte para continuar" después de haberse producido un error, que yo calificaría de GRAVÍSIMO, ya que afecta a los tipos de datos de los campos, y por tanto, a la estructura de la tabla EFE o de cualquier otra.

    ¡Eso no se puede o no se debería hacer! Si se ha producido ese error en el método CambiarTipoDatosAccessTabla_EFEParte2 , en mi opinión personal es una verdadera barbaridad que le indiques al usuario que continúe como si no hubiera pasado nada. ¿No te das cuenta que esa tabla puede estar en un estado inconsistente, donde unos campos se han modificado su tipo de datos y otros no, por lo que posteriormente el usuario puede obtener resultados inesperados.

    Ante cualquier error de éste tipo que afecte a la estructura de la propia base de datos, entiendo que lo correcto es FINALIZAR EL PROGRAMA SIN MÁS, previa escritura en algún archivo tipo *.log del error que se ha producido, ya que los datos existentes en cualquier informe que genere el usuario, puede que no sean todo lo exactos que debieran. ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.





    domingo, 2 de octubre de 2016 7:23
    Moderador
  • Hola maestro, buenos días:

    Ahora ha pasado correctamente por el procedimiento sin general error alguno, me muestra 330 registros afectados sin ningún error.

    Voy a seguir probando ya que esa es la que generaba un error y ahora ya no lo hace, he estado repasando los campos y están bien, aunque no acabo de entender por que con tu procedimiento "MetodosDatos.ExecuteAction(cmd)" y manda error cuando siempre va bien dicho procedimiento, si que es verdad que ahora es muy más rápido con executeNonQuery.

    Voy a hacer el resto de pruebas y a quitar el " ' " comentario de algunas de ellas que las tengo marcadas para ir detectando donde se localizan los errores. También voy a cambiar el mensaje ahora que lo tengo fresco, si no después se me olvida a lo mejor.

    No se coo leches se te ha ocurrido dicha idea, pero bueno, eres asi, cabezón y llegas hasta el final si o si.

    Maestro, muchas gracias como siempre, voy a repasar todo lo hecho hasta ahora porque estoy ahora en un éxtasis informático al ver que ese problema, ya está.

    Un abrazo.

    Gemma

    domingo, 2 de octubre de 2016 7:43
  • "gemma_campillo" escribió:

    > Voy a seguir probando ya que esa es la que generaba un error y ahora ya no lo hace,
    > he estado repasando los campos y están bien, aunque no acabo de entender por que
    > con tu procedimiento "MetodosDatos.ExecuteAction(cmd)" y manda error cuando siempre
    > va bien dicho procedimiento, si que es verdad que ahora es muy más rápido con executeNonQuery.

    El procedimiento MetodosDatos.ExecuteAction(cmd) siempre va bien, porque éste lo único que se limita es a configurar un objeto DbConnection apropiado y a ejecutar el método ExecuteNonQuery del objeto DbCommand especificado.

    Pero ten en cuenta que, como en dicho procedimiento también se configura un objeto Connection, con su correspondiente cadena de conexión, puede que ésta cadena de conexión sea DIFERENTE a aquella que tiene asignada el objeto Connection devuelto por el método da.CreateConnection() en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2().

    Es decir, en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2() se crea un objeto Connection, y en el método ExecuteAction() otro objeto Connection, que puede que tenga una cadena de conexión diferente que la que tiene el primer objeto Connection.

    Cuando ahora has dejado de llamar al método MetodosDatos.ExecuteAction es cuando ha funcionado todo, por lo que no me queda más que pensar que las cadenas de conexión de ambos objetos Connection sean diferentes: una configurada para Access (la del método CambiarTipoDatosAccessTabla_EFEParte2) y otra configurada para SQL Server o SQL Server Compact (la del método MetodosDatos.ExecuteAction), de ahí esos "mensajes de error extraños" del tipo "Demasiados campos definidos", que me suena más a un error de SQL Server que de Access. ;-)

    Si el problema se debía a esto, entiendo que NO DEBERÍAS CONFIGURAR un objeto Connection si posteriormente tienes pensado llamar al método MetodosDatos.ExecuteAction(), que se supone es el encargado de crear y configurar correctamente el objeto Connection que se va a utilizar para ejecutar una acción concreta.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo domingo, 2 de octubre de 2016 8:20
    domingo, 2 de octubre de 2016 8:02
    Moderador
  • Hola maestro:

    Pues esa sabia deducción que haces es correcta como siempre. Sabes demasiado y me cuesta seguirte, pero bueno para eso están las alumnas "aventajadas".

    Yo creo que las cadenas de conexión son las mismas, la establezco en el submain al arrancar y ya después me funciona desde el app.Config para toda la aplicación, de cualquier manera el o los dichosos errores me dan a pensar que voy a repasar en cuanto acabe esto, los executeaction.cmd porque nunca me han dado errores de nada pero si que te digo que la conexión en algunos lugares la abro dos veces, una el Cnn.Open del procedimiento y otra claro ejecutando tu executeaction.cmd.

    Bueno, hoy es un día de gran aprendizaje para mi. Te agradezco enormemente tu cabezonería en arreglar este tema, que por cierto, cuando todo hecho grabaré una entrada en el registro para que no pase más de una vez, puesto que la base de datos access, ya tendrá todos sus campos numeric como decimal en vez de double.

    Bueno, veré la mejor forma de hacerlo y con eso ya tendremos todo en decimal que era de lo que se trataba.

    Maestro, gracias infinitas otra vez.

    Gemma

    domingo, 2 de octubre de 2016 8:20
  • "gemma_campillo" escribió:

    > Yo creo que las cadenas de conexión son las mismas, la establezco en el submain
    > al arrancar y ya después me funciona desde el app.Config para toda la aplicación,
    > de cualquier manera el o los dichosos errores me dan a pensar que voy a repasar
    > en cuanto acabe esto, los executeaction.cmd porque nunca me han dado errores de
    > nada pero si que te digo que la conexión en algunos lugares la abro dos veces,
    > una el Cnn.Open del procedimiento y otra claro ejecutando tu executeaction.cmd.

    ¿Seguro que la cadenas de conexión son iguales? ;-)

    La conexión la abres DOS VECES porque estás utilizando DOS OBJETOS CONNECTION DIFERENTES, porque si fuera el mismo objeto Connection, obtendrías una "preciosa" InvalidOperationException la segunda vez que intentas abrir la conexión, ya que deberías de saber que un objeto Connection que ya está abierto, NO SE PUEDE ABRIR de nuevo hasta que no se cierre.

    Y deberías de examinar bien si estás o no utilizando la misma cadena de conexión. De todas maneras, NO DEBERÍAS LLAMAR al método compartido ExecuteAction de la clase o módulo llamado MetodosDatos si previamente has configurado un objeto DataAccessInvariant o como se llame la clase que referencia el objeto llamado 'da':

        ' Declaramos una variable Connection
        Using cnn As DbConnection = da.CreateConnection()

    ¿La variable 'da' es del tipo DataAccessInvariant, una clase que en su día te recomendé para trabajar con diferentes proveedores de datos? Si es así, una vez que hayas obtenido un objeto DbConnection invariable del proveedor de datos, estás en disposición de obtener fácilmente el objeto DbCommmand:

            ' Creamos el comando
            Dim cmd As DbCommand = cnn.CreateCommand()

    Pues si ya tienes una conexión (cnn) y un comando (cmd), no es necesario, ni deberías hacerlo, llamar al método compartido ExecuteAction de la clase o módulo llamado MetodosDatos, porque tan solo tienes que llamar al método ExecuteNonQuery del objeto DbCommand creado:

            ' Abrir la conexión
            cnn.Open()

            ' Configurar la propiedad CommandText
            cmd.CommandText = "ALTER TABLE ..."

            ' Ejecutar el comando
            cmd.ExecuteNonQuery()

        End Using  ' Destruir la conexión

    El método compartido ExecuteAction de la clase o módulo MetodosDatos lo podrás utilizar cuando NO TENGAS UN OBJETO CONNECTION DECLARADO de antemano, es decir, solamente tienes un objeto Command perteneciente a un proveedor de datos concreto (OleDbCommand, SqlCommand, SqlCeCommand, etc):

        ' Configurar un objeto OleDbCommand
        Using cmd As New OleDbCommand()
        
            ' Configurar la propiedad CommandText
            cmd.CommandText = "ALTER TABLE ..."
    
            ' Ejecutar el comando
            MetodosDatos.ExecuteAction(cmd)
    
        End Using

    Y sería en el método ExecuteAction donde se utilizaría un objeto OleDbConnection para abrir la conexión, ejecutar el comando especificado, destruir la conexión y devolver el número de registros afectados si procede, aunque también habría que ver la implementación definitiva que estás utilizando del método ExecuteAction, porque han sido tantas veces la que he modificado su implementación para adaptarla a las necesidades de la gente, como puede haber sido tu caso, que ya no sé ni la versión que puede estar utilizando cada una de ellas.

    Fíjate la diferencia entre crear un comando de una u otra manera:

            ' Creamos un comando asociado a un objeto OleDbConnection previamente declarado
            Dim cmd As OleDbCommand = cnn.CreateCommand()

            ' Creamos un comando que NO ESTÁ asociado a ningún objeto OleDbConnection
           Dim cmd As New OleDbCommand()

    Los dos son objetos OleDbCommand válidos, pero mientras el primero ya conoce cuál es su objeto OleDbConnection, al segundo hay que añadírselo posteriormente a través de su propiedad Connection:

           ' Le asignamos el objeto Connection al objeto Command
           cmd.Connection = cnn

    Salvo que se utilice la siguiente sobrecarga del constructor de la clase OleDbCommand:

           Dim cmd As New OleDbCommand(<Consulta SQL>, cnn)

    Pero lo dicho: ¿tienes un objeto Connection invariable? Si la respuesta es afirmativa, crea un objeto Command mediante el método CreateCommand del objeto DbConnection, y ejecuta su método ExecuteNonQuery.


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    domingo, 2 de octubre de 2016 9:34
    Moderador
  • Hola maestro:

    El objeto da es invariable:

    Region "CreateConnection"
    
        ''' <summary>
        ''' Devuelve un objeto Connection apropiado al tipo de factoría creada.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CreateConnection() As DbConnection
    
            ' Crear y devolver un objeto Connection.
            '
            Dim cnn As DbConnection = m_factory.CreateConnection()
            cnn.ConnectionString = m_connectionString
    
            Return cnn
    
        End Function
    
        ''' <summary>
        ''' Devuelve un objeto Connection apropiado de acuerdo al nombre
        ''' de la cadena de conexión existente en el archivo de
        ''' configuración de la aplicación.
        ''' </summary>
        ''' <param name="nameConnectionString">Nombre de la cadena de conexión.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function CreateConnection(nameConnectionString As String) As DbConnection
    
            ' Obtenemos los datos de la cadena de conexión desde
            ' el archivo de configuración de la aplicación.
            '
            Dim config As New Configuracion(nameConnectionString)
    
            Return DataAccessInvariant.CreateConnection(config.ProviderName, config.ConnectionString)
    
        End Function
    
        ''' <summary>
        ''' Devuelve un objeto Connection apropiado de acuerdo al
        ''' tipo de proveedor de datos que se haya especificado.
        ''' </summary>
        ''' <param name="providerInvariantName">Nombre invariable de
        ''' un proveedor, como por ejemplo System.Data.SqlClient.</param>
        ''' <param name="connString">Cadena de conexión con el origen de datos.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function CreateConnection(providerInvariantName As String,
                                                connString As String) As DbConnection
    
            Dim da As New DataAccessInvariant(providerInvariantName, connString)
            Return da.CreateConnection()
    
        End Function

    Y te adjunto la imagen de lo que lleva el objeto da cuando hago el debugger:

    Pero aún sigue dango el maldito error, aunque haya dejado nada más que este procedimiento para intentar ver que pasa con el. Todos llevan el mismo sistema de conexión y los otros van perfectos, he estado comprobando el nombre y es correcto (es donde está el punto de interrupción) y dejando solo este procedimiento en el primer registro casca.

    Te pongo para que no la tengas que buscar si te parece la imagen de Access con el tipo de campo, los anteriores ya los tiene como decimal y este como double.

    Si es problema de conexiones, por qué los otros no dan ningún problema. Pero maestro, yo veo que las conexiones nunca me han dado problemas. Ni uno, y hacen su función correctamente.

    Vale, y ahora pasa por la tira de registros que los tengo en varios procedimientos y casca en este y siempre es la misma tabla EFE. La he compactado por problemas de inconsistencia por si acaso y nada, no me dá error la compactación, pero en cambio en el registro marcado en la imagen, salta la excepción: "Demasiados campos definidos" y es eso lo que me vuelve tarumba, está todo igual que lo demás, le he puesto el bloque "finally" a todos para probar (después ya lo sacaré), y todos los messagebox me indicas: registros modificados 0, claro es, por que antes ya estaban modificados a decimal, por lo tanto funciona perfecto. Es en esta maldita tabla donde da los problemas y ya te digo, que los registro de la tabla EFE anteriores al marcado en negrita en Access, ya tienen su tipo de dato a "decimal (18,2)".

    Buen voy a segu8ir investigando y si tu tienes tiempo y ves algo, ya me lo dirás.

    Muchas gracias querido amigo.

    Gemma

    domingo, 2 de octubre de 2016 10:23
  • "gemma_campillo" escribió:

    > Vale, y ahora pasa por la tira de registros que los tengo en
    > varios procedimientos y casca en este y siempre es la misma tabla EFE.

    Pues según la imagen que has publicado, no entiendo ya a qué se puede deber el error que obtienes, porque la cadena de conexión apunta a la base de datos de Access que se comprende está en la misma carpeta que el ejecutable de la aplicación.

    > Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    >
    >        Try
    >
    >            ' Declaramos una variable Connection
    >            Using cnn As DbConnection = da.CreateConnection()
    >

    ¿Dónde y cómo creas la instancia de la clase "da"? ¿La tienes declarada a nivel global? Te lo pregunto porque no observo que se encuentra declarada e instanciada en el procedimiento CambiarTipoDatosAccessTabla_EFEParte2.

    > le he puesto el bloque "finally" a todos para probar (después ya lo sacaré),
    > y todos los messagebox me indicas: registros modificados 0, claro es, por
    > que antes ya estaban modificados a decimal, por lo tanto funciona perfecto.

    La verdad es que el método ExecuteNonQuery devuelve 0 registros afectados (o -1, no recuerdo ahora mismo) cuando ejecuta una consulta de definición de datos, como es el caso de la consulta ALTER TABLE, así que de nada sirve el valor de la variable 'n' tal cual aparece en el ejemplo.

    Tendrías que sumar una unidad posteriormente a la ejecución del método ExecuteNonQuery:

        With cmd
            .CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
            .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery() : n += 1
        End With
    


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.

    • Marcado como respuesta gemma_campillo domingo, 2 de octubre de 2016 14:44
    domingo, 2 de octubre de 2016 12:03
    Moderador
  • Hola Enrique:

    La instancia la creo a nivel de módulo(form, clase.)

      Public Shared Property da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)

    La he estado probando hace un ratito a nivel de método y es lo mismo, da el error. Lo que si estoy viendo es que eso solo me está pasando con 2 tablas que contienen más de 100 campos y no se si por ahí pueden venir los tiros, aunque cada executenonquery la estemos haciendo campo por campo y no sea que si la tabla tiene muchos campos detecte ese problema y proceda a emitir el error. Si tengo, por ejemplo en la tabla TAM: Ventas1, Ventas2, Venstas3,... resulta que los dos primeros campos los hace correctamente y salta la excepción siempre en el 3º en este caso Ventas3, repaso por activa t por pasiva el campo en Access, en el método, en finen todo lo que se pueda o sepa repasar y está todo bien, ahora cuando paso el breakpoint casca siempre en el mismo registro y eso solo pasa en esas 2 tablas: EFE y TAM, que llevan muchos registros, más de 200 y menos de 250. más o menos.

    Bueno, déjalo ya que voy a seguir buscando y probando, porque fíjate una cosa ya verás: Tildo todas las llamadas que hago a los otros métodos para las otras tablas, y en el método de la TAM (ese que ahora estamos hablando) dejo sin marcar solo Ventas3, lo demás todo marcado, por lo que por el único sitio que va a realizar una operación es en ese método que solo hay un AlterTable (el Ventas3), pues para tocar los que no suena, ahí vuelve a saltar el error (con un solo registro) por lo tanto, me lleva a pensar que el problema es otro (Quizás la cantidad de campos??), no lo sé si de alguna forma sabe el programa a priori la cantidad de campos de la tabla, me pierdo.

    Bueno, voy a seguir investigando porque ya verás que tiene que se algo de eso, no puede ser que con un solo registro salte el error.

    Querido amigo, descansa que ya vale.

    Un fuerte abrazo maestro.

    Gemma

    domingo, 2 de octubre de 2016 14:44
  • "gemma_campillo" escribió:

    > La instancia la creo a nivel de módulo(form, clase.)
    >
    Public Shared Property da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)

    ¡Madre mía! ¿Tu sabes realmente lo que significa esa declaración?

    Estás compartiendo (Shared) una propiedad (Property) pública (Public) que puede ser leída (Get) y puede ser modificada (Set) desde cualquier parte de tu aplicación, y por si no fuera bastante, la estás implementando como una  propiedad autoimplementada automáticamente, por lo te será complicado acceder al campo privado que el compilador de Visual Basic habrá creado automáticamente para devolver y establecer el valor de dicha propiedad.

    Gemma, yo comprendo que es muy fácil trabajar con ese tipo de declaraciones, pero precisamente, en esa facilidad es donde se encuentra el peligro, porque por mucho que digas que funciona perfectamente, ¿puedes estar segura de que no se ha modificado sin querer el valor de la propiedad 'da' en alguna parte de tu proyecto sin que seas consciente de ello?

    Te he comentado antes, e insisto en ello, que el mensaje de error "Demasiados campos definidos", me suena más a SQL Server que a Access, y como te encuentras trabajando con 3 tipos de bases de datos diferentes, ¿no puedes pensar que el valor de la propiedad compartida 'da' se haya modificado y su cadena de conexión esté apuntando a una base de SQL Server?

    Por la imagen que has publicado anteriormente, ya sé que la cadena apunta a una base de Access, pero mejor será que coloques un punto de interrupción en una llamada cualquiera al método ExecuteNonQuery, y compruebes el valor que tiene la propiedad ConnectionString de la propiedad Connection del objeto DbCommand, es decir, en la Ventana Inmediato consulta el siguiente valor:

        ?cmd.Connection.ConnectionString

    y pulsa la tecla Enter para ver qué valor tiene actualmente la cadena de conexión del objeto Connection actual.

    Te comento que la clase DataAccessInvariant no consume recursos a la hora de crear una instancia de la misma, ni la clase abre conexiones que después haya que cerrar y destruir, por lo que en mi opinión personal no tiene ningún sentido que utilices una propiedad compartida de lectura y escritura para ahorrarte tener que declarar y crear una nueva instancia de la clase DataAccessInvariant cada vez que la vayas a utilizar. Es decir, que en lugar de mantener a nivel del proyecto la declaración que estás utilizando, mi opinión es que en cada método que vayas a hacer uso de la clase DataAccessInvariant crees una nueva instancia de ella:

        Public Sub NombreMetodo()
    
    ' Declarar y crear una nueva instancia de la clase DataAccessInvariant.
    Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion) Using cnn As DbConnection = da.CreateConnection() Dim cmd As DbCommand = cnn.CreateCommand() cmd.CommandText = "ALTER TABLE ..." cnn.Open() cmd.ExecuteNonQuery() End Using End Sub

    Esta es la manera de asegurarte que en ninguna otra parte de tu proyecto se ha modificado sin querer el valor que va a ser utilizado para la instancia de la clase DataAccessInvariant creada, lo que también es válido para otros tipos de objetos diferentes.

    > La he estado probando hace un ratito a nivel de método y es lo mismo, da el error.
    > Lo que si estoy viendo es que eso solo me está pasando con 2 tablas que contienen
    > más de 100 campos y no se si por ahí pueden venir los tiros, aunque cada executenonquery
    > la estemos haciendo campo por campo y no sea que si la tabla tiene muchos campos detecte
    > ese problema y proceda a emitir el error.

    Que yo sepa, no existe un número exacto de veces que puedes llamar al método ExecuteNonQuery; lo puedes llamar tantas veces como desees. Y en cuanto al número de campos de la tabla, mientras que no supere los 255 campos, no tienes por qué tener problemas.

    Dices que solamente te pasa con 2 tablas: EFE y TAM. Me ha dado por mirar si los nombres son palabras reservada de Access, y te digo que no lo son:

    Palabras y símbolos reservados de Access 2007

    Si has podido modificar el tipo de dato de los campos existentes en otras tablas diferentes utilizando la consulta

        ALTER TABLE [NombreTabla] ALTER COLUMN [NombreCampo] Decimal(18,2) DEFAULT 0

    entonces el problema no es de la sintaxis de la consulta ALTER TABLE, por lo que el problema tiene que estar en todo el proceso de actualizar los tipos de datos de los campos correspondientes a las tablas EFE y TAM.

    Para ver si eres capaz de modificar los tipos de datos de esas tabla, crea un nuevo proyecto de Visual Basic, e inserta en el formulario de inicio el siguiente procedimiento:

    Imports System.Data.OleDb
    
    Public Class Form1
    
        Public Shared Sub CambiarTipoDatosAccessTabla_EFEParte2()
    
            ' Para contar el número de campos actualizados. Cuando
            ' esté el código depurado, eliminar la variable local.
            '
            Dim n As Integer
    
            Try
                ' Declaramos una variable Connection
                Using cnn As New OleDbConnection(escribe aquí la cadena de conexión con la base de Access)
    
                    ' Creamos el Commando
                    Dim cmd As OleDbCommand = cnn.CreateCommand()
    
                    ' Abrir la conexión
                    cnn.Open()
    
                    With cmd
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResLegalEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResVoluntEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResEspecEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResEstatutEjAnt Decimal(18,2)  DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResFdoComercEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column RemanenteEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column ResNegativEjAnt Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmIntangible Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInmMater Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                        .CommandText = "ALTER TABLE EFE ALTER  Column CtdoVContCpraInvInmob Decimal(18,2) DEFAULT 0" : .ExecuteNonQuery(): n += 1
                    End With
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: '965a1p" & vbCrLf & ex.Message & vbCrLf &
                       "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
    
            Finally
                ' Cuando el código esté totalmente depurado, eliminar el bloque Finally.
                MessageBox.Show("Nº de campos modificados: " & CStr(n))
    
            End Try
    
        End Sub
    
    End Class

    Y desde el evento Click de cualquier control Button llama al método CambiarTipoDatosAccessTabla_EFEParte2.

    Esto es lo que exactamente hice ayer y no tuve ningún tipo de problema para asignar el tipo de dato Decimal a los 10 campos de la tabla EFE. Inténtalo, y si observas que se modifican, entonces el problema lo tienes en tu aplicación. ¿Dónde? ¡Ni idea! ;-)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.



    domingo, 2 de octubre de 2016 16:25
    Moderador
  • Hola Enrique:

    Bueno, el tema de la conexión ya lo tenía en cada procedimiento y aún los tengo tildados. Lo puse como ahora está, porque en cada procedimiento iba y venía pasando todas las veces por la conexión, el proveedor invariable, etc. Hasta ahora no te tenido problemas, pero entiendo perfectamente lo que me has indicado, por lo tanto desmarcaré las conexiones de los procedimientos y ya estará.

    Voy a probar todo lo que me has escrito a ver si de una vez lo soluciono.

    Maestro, gracias por todo tu tiempo empleado conmigo, que te voy a decir.

    En cuanto pueda, te comento como ha ido.

    Gracias Enrique y un fuerte abrazo.

    Gemma

    domingo, 2 de octubre de 2016 17:01