none
Conversión de datos de lista genérica en decimal

    Pregunta

  • Hola a todos:

    Estoy cambiando los datos de la aplicación de double a decimal y me topo que en el momento de cargar una lista me da el error:

    "Error al convertir los datos, [OLE DB status value (if Known) = 0 ]".

    Dicho error me sale con una conexión a sqlcompact. Si la conexión la hago con Access no da ningún error.

    Pongo el código de la clase para crear a lista y una línea de la lista para que no sea repetitivo. El campo o propiedad "BeneficioOrdinario(0)" lógicamente también es decimal y va con una precisión(18,5).

     Public Shared Sub UmbralRentabilidad_ActualizacionValoresTabla()
            Try
                Dim lst As New List(Of ActualizarTablaVarios_UmbralRentabilidad)
                Dim empresa As String = VarGlobal.StrCodEmpresa
    
                                  lst.Add(New ActualizarTablaVarios_UmbralRentabilidad(BeneficioOrdinario(0), empresa, "443"))
                        
    
                Using cnn As DbConnection = da.CreateConnection()
                    cnn.Open()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand()
    
                    For Each item As ActualizarTablaVarios_UmbralRentabilidad In lst
    
                        cmd.CommandText = item.Update()
    
                        cmd.ExecuteNonQuery()
    
                    Next
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula:     'ListasOF UmbralRentabilidad'" & vbCrLf & ex.Message & vbCrLf &
                        "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
    
            End Try
        End Sub

    y el código de la clase para crear la lista es:

    Public Class ActualizarTablaVarios_UmbralRentabilidad
        Private m_ejer1 As Decimal
        Private m_empresa As String
        Private m_orden As String
    
        Public Sub New(ejer1 As Decimal, empresa As String, orden As String)
    
            m_ejer1 = ejer1
            m_empresa = empresa
            m_orden = orden
    
        End Sub
    
        Public ReadOnly Property ejer1 As Decimal
            Get
                Return m_ejer1
            End Get
        End Property
    
        Public ReadOnly Property empresa As String
            Get
                Return m_empresa
            End Get
        End Property
    
        Public ReadOnly Property orden As String
            Get
                Return m_orden
            End Get
        End Property
    
    
        Public Function Update() As String
    
            ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.
    
            Return String.Format("UPDATE Varios Set Ejer_01='{0}' WHERE Cod_Empresa='{1}' AND Orden='{2}'",
                                m_ejer1, m_empresa, m_orden)
    
        End Function
    End Class

    No entiendo, ya que he probado con anteponerle el Cdec y siempre me da error y también porqué con los mismos valores y tipos de campos en Access no da error.

    Bueno, muchas gracias a todos.

    Gemma




    sábado, 8 de octubre de 2016 17:57

Respuestas

  • "gemma_campillo" escribió:

    > Estoy cambiando los datos de la aplicación de double a decimal y me topo que en
    > el momento de cargar una lista me da el error:
    >
    >    "Error al convertir los datos, [OLE DB status value (if Known) = 0 ]".
    >
    > Dicho error me sale con una conexión a sqlcompact. Si la conexión la hago con
    > Access no da ningún error.

    Te advierto ya de antemano que un error parecido, aunque más descriptivo que el que obtienes con SQL Server Compact, te va aparecer cuando intentes ejecutar la misma consulta UPDATE con una base de datos de SQL Server:


    Aquí se ve muchísimo mejor el motivo del error, el cual consiste en que estás queriendo convertir un valor alfanumérico (nvarchar, varchar, char) en decimal (numeric), y en principio no hay ningún problema para ello, siempre y cuando el valor alfanumérico se pueda convertir en decimal.

    Vamos a estudiar el valor devuelto por la función Update existente en la clase ActualizarTablaVarios_UmbralRentabilidad:

        Public Function Update() As String

            ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.

            Return String.Format("UPDATE Varios Set Ejer_01='{0}', Ejer_02='{1}', Ejer_03='{2}', Ejer_04='{3}',
                                 Ejer_05='{4}', Ejer_06='{5}', Ejer_07='{6}', Ejer_08='{7}', Ejer_09='{8}',
                                 Ejer_10='{9}', Ejer_11='{10}',Ejer_12='{11}' WHERE Cod_Empresa='{12}' AND Orden='{13}'",
                                 m_ejer1, m_ejer2, m_ejer3, m_ejer4, m_ejer5, m_ejer6, m_ejer7, m_ejer8, m_ejer9,
                                 m_ejer10, m_ejer11, m_ejer12, m_empresa, m_orden)
        End Function

    Al estar utilizando el método String.Format para devolver el valor de la función Update, éste será un valor ALFANUMÉRICO, aunque lleve números decimales encerrados entre comillas simples:

         ..., '232,342', '1223,234', '11234,76', ...

    Y si esos números decimales están separados por la coma decimal, como los que aparecen en el ejemplo, entonces no podrás convertirlos a decimal, de ahí el mensaje de error que estás obteniendo con SQL Server Compact y que también obtendrás con SQL Server, no así en Access, que no sé si para bien o para mal, sí permite este tipo de conversión.

    A estas alturas deberías de saber que, a efectos de programación y de almacenaje en una base de datos, los números decimales se escriben con el PUNTO DECIMAL, y no con la COMA DECIMAL, por lo que tendrías que escribirlos así:

         ..., '232.342', '1223.234', '11234.76', ...

    sin que sea necesario encerrarlos entre comillas simples porque son VALORES NUMÉRICOS no VALORES ALFANUMÉRICOS:

         ..., 232.342, 1223.234, 11234.76, ...

    De ésta manera verás como no obtienes ningún tipo de error.

    Te funciona con Access porque los valores numéricos los estás encerrando entre comillas simples, porque de no ser así y si los números llevan la COMA DECIMAL, obtendrás un error de sintaxis.

    Lo siguiente tampoco funcionará en Access:

         ..., 232,342, 1223,234, 11234,76, ...

    porque en lugar de 3 campos, Access y cualquier otro motor de datos, entiende que son 6 campos, ya que los valores están separados por comas. Por este motivo se utiliza el punto decimal para especificar los valores numéricos decimales, y la coma decimal, se usa para separar los valores de los diversos campos. ¿Me explico?

    Solución. A mi entender, yo te aconsejaría que te olvidaras de listas genéricas y que utilizaras una consulta SQL con parámetros, donde los valores de éstos los añadirías a la colección Parameters del objeto DbCommand que vayas a utilizar para ejecutar la consulta. ¿Que no deseas utilizar parámetros? Entonces no te va a quedar más remedio que reemplazar la coma decimal por el punto decimal en aquellos valores correspondientes a los campos de la tabla que tengan el tipo de dato numeric o decimal.

    En la función String.Format existente en el método Update, los campos de la tabla con el tipo de dato Decimal o Numeric, tienes que convertirlos previamente a String para posteriormente ejecutar su método Replace y reemplazar la coma por el punto decimal. Para los tres primeros campos de la consulta UPDATE, sería:

       
    m_ejer1.ToString().Replace(",", "."), m_ejer2.ToString().Replace(",", "."), m_ejer3.ToString().Replace(",", "."), ...

    ¡Menudo jaleo!

    Por cierto, en tu función Update observo el siguiente comentario:

    > ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.

    Quiero recordar que eso te lo dije yo en alguna de las tantas respuestas que te llevo ofrecidas, pero no recuerdo el motivo por el cual lo escribí, quizás para que encerraras entre comillas simples los VALORES ALFANUMÉRICOS, pero no los VALORES NUMÉRICOS.

    De todas maneras, no entiendo yo esa especie de "capricho" que te ha dado por utilizar "listas genéricas", como si fuera la panacea para resolver todos los problemas de ejecución de consultas SQL, cuando lo correcto y más sencillo es ejecutar la clásica consulta SQL con parámetros.

    ¿Por cada tabla de tu base de datos tienes creada una clase como la clase ActualizarTablaVarios_UmbralRentabilidad que has mostrado en tu mensaje?


    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, 9 de octubre de 2016 7:26
    Moderador
  • "gemma_campillo" escribió:

    > No se por qué me metes el miedo en el cuerpo cuando la "fórmula" que me
    > has escrito funciona a la perfección.
    >
    > Mira, la he probado en las 3 bases de datos y no da ningún error y graba
    > los datos perfectamente. Esa solución que has puesto es perfecta.

    ¡Claro que funciona! Mientras que los valores alfanuméricos que representan números decimales estén representados mediante su correspondiente PUNTO DECIMAL, ¿qué problema vas a tener? ¡Ninguno! Pero siguen siendo "parches para salir del paso", como te he comentado en la anterior respuesta, ya que la cantidad de ...ToString().Replace(",", ".") que vas a tener que introducir es bastante considerable.

    > Eres un genio aunque a veces me asustas. Bueno, es broma.

    ¡Mujer! No pretendo asustar a nadie, más bien decir las cosas claras, aunque ésto "asuste" al personal. ;-)


    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, 9 de octubre de 2016 9:34
    Moderador
  • "gemma_campillo" escribió:

    > Si no dices nada al contrario, rectifico las clases de las listas y a correr.
    > Que alegría me he llevado cuando he visto los valores grabados perfectamente.

    ¡Bueno! Como parece ser que te "he asustado", voy a compensarlo con algo que quizás te produzca una alegría mayor.

    Me ha venido a la mente otro "parche" para que no tengas que convertir a String y llamar al método Replace. Para ello, tendrás que sustituir tu función Update por ésta otra implementación:

        Public Function Update() As DbCommand
    
            ' Crear el comando invariable
            Dim cmd As DbCommand = da.CreateCommand()
    
            cmd.CommandText = "UPDATE Varios " &
                              "SET Ejer_01=@p1, Ejer_02=@p2, Ejer_03=@p3, Ejer_04=@p4," &
                              "Ejer_05=@p5, Ejer_06=@p6, Ejer_07=@p7, Ejer_08=@p8, Ejer_09=@p9," &
                              "Ejer_10=@p10, Ejer_11=@p11,Ejer_12=@p12" &
                              "WHERE Cod_Empresa=@p13 And Orden=@p14"
    
            With cmd.Parameters
                .Add(da.CreateParameter("@p1", m_ejer1))
                .Add(da.CreateParameter("@p2", m_ejer2))
                .Add(da.CreateParameter("@p3", m_ejer3))
                .Add(da.CreateParameter("@p4", m_ejer4))
                .Add(da.CreateParameter("@p5", m_ejer5))
                .Add(da.CreateParameter("@p6", m_ejer6))
                .Add(da.CreateParameter("@p7", m_ejer7))
                .Add(da.CreateParameter("@p8", m_ejer8))
                .Add(da.CreateParameter("@p9", m_ejer9))
                .Add(da.CreateParameter("@p10", m_ejer10))
                .Add(da.CreateParameter("@p11", m_ejer11))
                .Add(da.CreateParameter("@p12", m_ejer12))
                .Add(da.CreateParameter("@p13", m_empresa))
                .Add(da.CreateParameter("@p14", m_orden))
            End With
    
            Return cmd
    
        End Function

    Revisa que haya escrito bien la sintaxis de la consulta UPDATE.

    Se comprende que estás haciendo uso de una variable, campo o propiedad llamada "da" a nivel global que contiene una instancia válida de la clase DataAccessInvariant.

    Esto requiere que tu clase DataAccessInvariant disponga de los siguiente métodos:

    #Region "CreateCommand"
    
        ''' <summary>
        ''' Devuelve un objeto Command apropiado al tipo de factoría creada.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CreateCommand() As DbCommand
    
            ' Crear y devolver un objeto Command.
            '
            Return m_factory.CreateCommand()
    
        End Function
    
    #End Region
    
    #Region "CreateParameter"
    
        ''' <summary>
        ''' Devuelve un objeto DbParameter apropiado al tipo de factoría creada.
        ''' </summary>
        ''' <param name="name">Nombre del parámetro.</param>
        ''' <param name="value">Valor del parámetro.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CreateParameter(name As String, value As Object) As DbParameter
    
            ' Crear y devolver un objeto Parameter.
            '
            Dim param As DbParameter = m_factory.CreateParameter()
            param.ParameterName = name
            param.Value = value
    
            Return param
    
        End Function
    
    #End Region

    Y cuando desees actualizar la tabla de la base de datos, ejecutarías lo siguiente:

            Using cnn As DbConnection = da.CreateConnection()
    
                cnn.Open()
    
                ' Creamos el Commando
                Dim cmd As DbCommand = Update()
    
                ' Le asignamos la conexión
                cmd.Connection = cnn
    
                ' Resto del código


    Antes de cambiar los métodos Update que tengas dispersos en todas tus clases, prueba con alguno de ellos para ver si tienes problemas utilizando consultas SQL con parámetros.


    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, 9 de octubre de 2016 10:03
    Moderador
  • "gemma_campillo" escribió:

    > Lo que me sabe mal es que digas que voy dando palos de ciego, no es así Enrique, ...

    ¡Bueno! Quizás leyendo mi comentario se distorsione lo que he querido decir más que si te lo hubiera dicho en una charla personal, cara a cara, tomándonos un café o una cerveza tranquilamente. Lo mismo no te hubiera sabido tal mal. ;-)

    Que conste que yo he hecho ese comentario en base al que tu has hecho anterior:

    > Maestro, menuda leche es esto, llevo desde ayer probando y probando
    > cosas sin saber a ciencia cierta que es lo que hago.

    Cuando una persona no sabe a ciencia cierta lo que está haciendo, lo más probable es que llegue a "pegar palos de ciego" si ya no lo está dando, sin que ello suponga una ofensa, desprecio, ni nada que se parezca. Al menos, así lo pienso yo.

    Y te lo digo a ti y no a otras personas, quizás por confianza y porque personalmente conozco tu trabajo y me gustaría que las cosas que haces (a nivel de programación, obviamente) las tuvieras bien claras. Pero nada más.


    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, 9 de octubre de 2016 10:27
    Moderador
  • "gemma_campillo" escribió:

    > Voy a probar lo que me has indicado para los parámetros, pero entiendo que
    > tampoco me están dando problemas en las 3 bases de datos, con poner simplemente
    > ToString después de la variable:

    No me refiero a que sustituyas el ToString, aunque desde luego, entiendo que está de más como te he indicado anteriormente.

    Me refiero a que sustituyas el método Update que aparece en la clase ActualizarTablaVarios_UmbralRentabilidad por el que te he indicado, para que no tengas que hacer multitud de conversiones inútiles (de Decimal, Integer, Long, etc. a String) para poder utilizar el método Replace de la clase String. Ten en cuenta que el hacer la conversión y ejecutar el método Replace también lleva su tiempo. No es que sea mucho lo que se tarde pero si hablamos de una considerable cifra de conversiones más Replace, puede que el tiempo de respuesta ya sea un poco superior.

    Aparte que considero que como se debe de trabajar es con parámetros, no con consultas SQL donde se concatenan los valores, por lo que estos serán tomados SIEMPRE como valores alfanuméricos. El String.Replace es para que puedes cambiar las posibles comas por el punto decimal, pero no quita que el valor decimal continúe siendo alfanumérico cuando en realidad debe ser el que se corresponda con el tipo de dato que tiene el campo en la tabla: Decimal, Integer, String, etc.


    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, 9 de octubre de 2016 10:51
    Moderador

Todas las respuestas

  • "gemma_campillo" escribió:

    > Estoy cambiando los datos de la aplicación de double a decimal y me topo que en
    > el momento de cargar una lista me da el error:
    >
    >    "Error al convertir los datos, [OLE DB status value (if Known) = 0 ]".
    >
    > Dicho error me sale con una conexión a sqlcompact. Si la conexión la hago con
    > Access no da ningún error.

    Te advierto ya de antemano que un error parecido, aunque más descriptivo que el que obtienes con SQL Server Compact, te va aparecer cuando intentes ejecutar la misma consulta UPDATE con una base de datos de SQL Server:


    Aquí se ve muchísimo mejor el motivo del error, el cual consiste en que estás queriendo convertir un valor alfanumérico (nvarchar, varchar, char) en decimal (numeric), y en principio no hay ningún problema para ello, siempre y cuando el valor alfanumérico se pueda convertir en decimal.

    Vamos a estudiar el valor devuelto por la función Update existente en la clase ActualizarTablaVarios_UmbralRentabilidad:

        Public Function Update() As String

            ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.

            Return String.Format("UPDATE Varios Set Ejer_01='{0}', Ejer_02='{1}', Ejer_03='{2}', Ejer_04='{3}',
                                 Ejer_05='{4}', Ejer_06='{5}', Ejer_07='{6}', Ejer_08='{7}', Ejer_09='{8}',
                                 Ejer_10='{9}', Ejer_11='{10}',Ejer_12='{11}' WHERE Cod_Empresa='{12}' AND Orden='{13}'",
                                 m_ejer1, m_ejer2, m_ejer3, m_ejer4, m_ejer5, m_ejer6, m_ejer7, m_ejer8, m_ejer9,
                                 m_ejer10, m_ejer11, m_ejer12, m_empresa, m_orden)
        End Function

    Al estar utilizando el método String.Format para devolver el valor de la función Update, éste será un valor ALFANUMÉRICO, aunque lleve números decimales encerrados entre comillas simples:

         ..., '232,342', '1223,234', '11234,76', ...

    Y si esos números decimales están separados por la coma decimal, como los que aparecen en el ejemplo, entonces no podrás convertirlos a decimal, de ahí el mensaje de error que estás obteniendo con SQL Server Compact y que también obtendrás con SQL Server, no así en Access, que no sé si para bien o para mal, sí permite este tipo de conversión.

    A estas alturas deberías de saber que, a efectos de programación y de almacenaje en una base de datos, los números decimales se escriben con el PUNTO DECIMAL, y no con la COMA DECIMAL, por lo que tendrías que escribirlos así:

         ..., '232.342', '1223.234', '11234.76', ...

    sin que sea necesario encerrarlos entre comillas simples porque son VALORES NUMÉRICOS no VALORES ALFANUMÉRICOS:

         ..., 232.342, 1223.234, 11234.76, ...

    De ésta manera verás como no obtienes ningún tipo de error.

    Te funciona con Access porque los valores numéricos los estás encerrando entre comillas simples, porque de no ser así y si los números llevan la COMA DECIMAL, obtendrás un error de sintaxis.

    Lo siguiente tampoco funcionará en Access:

         ..., 232,342, 1223,234, 11234,76, ...

    porque en lugar de 3 campos, Access y cualquier otro motor de datos, entiende que son 6 campos, ya que los valores están separados por comas. Por este motivo se utiliza el punto decimal para especificar los valores numéricos decimales, y la coma decimal, se usa para separar los valores de los diversos campos. ¿Me explico?

    Solución. A mi entender, yo te aconsejaría que te olvidaras de listas genéricas y que utilizaras una consulta SQL con parámetros, donde los valores de éstos los añadirías a la colección Parameters del objeto DbCommand que vayas a utilizar para ejecutar la consulta. ¿Que no deseas utilizar parámetros? Entonces no te va a quedar más remedio que reemplazar la coma decimal por el punto decimal en aquellos valores correspondientes a los campos de la tabla que tengan el tipo de dato numeric o decimal.

    En la función String.Format existente en el método Update, los campos de la tabla con el tipo de dato Decimal o Numeric, tienes que convertirlos previamente a String para posteriormente ejecutar su método Replace y reemplazar la coma por el punto decimal. Para los tres primeros campos de la consulta UPDATE, sería:

       
    m_ejer1.ToString().Replace(",", "."), m_ejer2.ToString().Replace(",", "."), m_ejer3.ToString().Replace(",", "."), ...

    ¡Menudo jaleo!

    Por cierto, en tu función Update observo el siguiente comentario:

    > ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.

    Quiero recordar que eso te lo dije yo en alguna de las tantas respuestas que te llevo ofrecidas, pero no recuerdo el motivo por el cual lo escribí, quizás para que encerraras entre comillas simples los VALORES ALFANUMÉRICOS, pero no los VALORES NUMÉRICOS.

    De todas maneras, no entiendo yo esa especie de "capricho" que te ha dado por utilizar "listas genéricas", como si fuera la panacea para resolver todos los problemas de ejecución de consultas SQL, cuando lo correcto y más sencillo es ejecutar la clásica consulta SQL con parámetros.

    ¿Por cada tabla de tu base de datos tienes creada una clase como la clase ActualizarTablaVarios_UmbralRentabilidad que has mostrado en tu mensaje?


    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, 9 de octubre de 2016 7:26
    Moderador
  • Hola Enrique, buenos días.

    Gracias como siempre. Me tiene aturdida este tema que a parecer tenía pinta de ser simple, pero no es así.

    Tengo una lista genérica para cada procedimiento en el que grabo los datos que se presentan en el form que sea, es decir, que si, que hay una clase por cada grabación en el form. Hay que tienen 150 elementos y hay otras con menos.

     Con Access es una delicia, bien por los motivos que me has expuesto o por lo que sea, pero me iba de perlas. Ahora el problema e plantea si tengo que volver a montar las grabaciones de datos en sus procedimientos, hay muchos. Si que es verdad que tengo algún procedimiento que graba en la tabla que sea y no me da error alguno, lo hago por ejemplo incluyendo en el parámetro "tostring", entonces en cualquier base de datos lo hace correctamente.

    Ejemplo: Te remarco el ToString de los parámetros.

    ublic Shared Sub ActualizarEOAF_AcreedComOtrasCtasPagar_PCO()
            Try
                Dim DiferAcreedComOtrasCtasPagar_PCO As Decimal = AcreedComOtrasCtasPagar_PCO(0) - AcreedComOtrasCtasPagar_PCO(1)
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand
    
                    If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
                        If DiferAcreedComOtrasCtasPagar_PCO >= 0 Then
                            cmd.CommandText = ("UPDATE EOAF SET Ejer_01 = @Ejer01, Ejer_02 = @Ejer02, Desv1 = @Difer, DismCirc = @Difer, AumCirc = '0' WHERE Cod_Empresa = @empresa AND Orden = '251'")
                        ElseIf DiferAcreedComOtrasCtasPagar_PCO < 0 Then
                            cmd.CommandText = ("UPDATE EOAF SET Ejer_01 = @Ejer01, Ejer_02 = @Ejer02, Desv1 = @Difer, AumCirc = abs(@Difer), DismCirc = '0' WHERE Cod_Empresa = @empresa AND  Orden = '251'")
                        End If
    
                        With cmd.Parameters
                            ' Acreedores comerc.y otras cuentas a pagar
                            .Clear()
                            .Add(Configuracion.CreateParameter(cmd, "@Ejer01", AcreedComOtrasCtasPagar_PCO(0).ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@Ejer02", AcreedComOtrasCtasPagar_PCO(1).ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@Difer", DiferAcreedComOtrasCtasPagar_PCO.ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@empresa", VarGlobal.StrCodEmpresa))
                        End With
    
                    ElseIf VarGlobal.StrPlanConta = "ENTPUB_10" Then
                        If DiferAcreedComOtrasCtasPagar_PCO >= 0 Then
                            cmd.CommandText = ("UPDATE EOAF SET Ejer_01 = @Ejer01, Ejer_02 = @Ejer02, Desv1 = @Difer, DismCirc = @Difer, AumCirc = '0' WHERE Cod_Empresa = @empresa AND Orden = '087'")
                        ElseIf DiferAcreedComOtrasCtasPagar_PCO < 0 Then
                            cmd.CommandText = ("UPDATE EOAF SET Ejer_01 = @Ejer01, Ejer_02 = @Ejer02, Desv1 = @Difer, AumCirc = abs(@Difer), DismCirc = '0' WHERE Cod_Empresa = @empresa AND  Orden = '087'")
                        End If
    
                        With cmd.Parameters
                            ' Acreedores comerc.y otras cuentas a pagar
                            .Clear()
                            .Add(Configuracion.CreateParameter(cmd, "@Ejer01", AcreedComOtrasCtasPagar_PCO(0).ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@Ejer02", AcreedComOtrasCtasPagar_PCO(1).ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@Difer", DiferAcreedComOtrasCtasPagar_PCO.ToString))
                            .Add(Configuracion.CreateParameter(cmd, "@empresa", VarGlobal.StrCodEmpresa))
                        End With
                    End If
    
                    ' Asignamos la conexión al comando
                    cmd.Connection = cnn
                    cnn.Open()
                    cmd.ExecuteNonQuery()
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: '1434'" & vbCrLf & ex.Message & vbCrLf &
                           "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

    Claro, ahora el problema es que hay en las listas unos 150 updates como el citado, que está resumido, pero menudo coñazo ahora volver a lo que ya tenía, por la historia de la conversión de datos.

    Bueno, no se si se te ocurre alguna cosa y si me dices que no, me pondré a volver a crear los updates tal como el ejemplo que he adjuntado.

    Maestro, menuda leche es esto, llevo desde ayer probando y probando cosas sin saber a ciencia cierta que es lo que hago.

    Bueno querido amigo muchas gracias como siempre y si no me indicas lo contrario, me pongo a cambiar las listas por los updates.

    Un fuerte abrazo Enrique.

    Gemma

    domingo, 9 de octubre de 2016 7:52
  • Enrique, el tema de: ' Devolver una cadena con los valores de los campos encerrados entre comillas simples.

    no hagas caso que era para que los acentos de las descripciones no dieran error, etc.

    Ese comentario no va ahí, lo he sacado.

    Un abrazo.

    Gemma.

    domingo, 9 de octubre de 2016 7:58
  • Estimado Enrique:

    No se por qué me metes el miedo en el cuerpo cuando la "fórmula" que me has escrito funciona a la perfección.

    Mira, la he probado en las 3 bases de datos y no da ningún error y graba los datos perfectamente. Esa solución que has puesto es perfecta. Lo único que tengo que hacer en cada clase que sea para actualizar, cambiar el m_ejer1, por el reemplazamiento que me has puesto y eso es coser y cantar, ya que la construcción de casi todas ellas es bastante parecida en cuanto a los ejercicios que son los que daban problemas.

    Siendo así, no tengo que volver a crear los updates en los procedimientos, ya que con la conversión que has hecho funciona perfectamente.

    Eres un genio aunque a veces me asustas. Bueno, es broma.

    Si no dices nada al contrario, rectifico las clases de las listas y a correr. Que alegría me he llevado cuando he visto los valores grabados perfectamente.

    Voy a seguir probando y viendo la presentación en las grillas.

    Gracias maestro.

    Un fuertísimo abrazo.

    Gemma

    domingo, 9 de octubre de 2016 8:25
  • "gemma_campillo" escribió:

    > No se por qué me metes el miedo en el cuerpo cuando la "fórmula" que me
    > has escrito funciona a la perfección.
    >
    > Mira, la he probado en las 3 bases de datos y no da ningún error y graba
    > los datos perfectamente. Esa solución que has puesto es perfecta.

    ¡Claro que funciona! Mientras que los valores alfanuméricos que representan números decimales estén representados mediante su correspondiente PUNTO DECIMAL, ¿qué problema vas a tener? ¡Ninguno! Pero siguen siendo "parches para salir del paso", como te he comentado en la anterior respuesta, ya que la cantidad de ...ToString().Replace(",", ".") que vas a tener que introducir es bastante considerable.

    > Eres un genio aunque a veces me asustas. Bueno, es broma.

    ¡Mujer! No pretendo asustar a nadie, más bien decir las cosas claras, aunque ésto "asuste" al personal. ;-)


    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, 9 de octubre de 2016 9:34
    Moderador
  • Hola maestro:

    Bueno, te has despachado a gusto, pero te he de hacer unas cuantas aclaraciones.

    1)"El problema que yo veo es que parece ser que confundes una instancia individual de una clase A o B con una lista genérica, cuando una lista genérica es una especie de colección de varios elementos comunes, pero si tienes una sola instancia (un único elemento), ¿para qué quieres una lista genérica?

    Lo que he puesto referente al registro de la lita genérica que nos ha ocupado, es solamente a titulo de ejemplo, esa lista es considerable y evidentemente con mas de 1 solo registro. Por lo que creo que las tengo bien hechas sin contar las conversiones que se tienen o se están haciendo para que funcionen en las 3 bases de datos.

    2) Yo creo que el programa está bien hecho, principalmente porque en las cosas importantes referentes al código has sido tu el que siempre has estado encima ayudándome, por lo que quieras  o no, mi forma de programar en principio me la has enseñado tú únicamente y algún libro que nunca ponen lo que necesito. Por lo tanto, creo que está bastante bien hecho, no me voy a extender más en este tema., pero si decirte que las soluciones importantes a mi entender son tuyas.

    Por otro lado, olvida el Vb6 porque de el lo único que he aprovechado son las fórmulas, lo demás está hecho desde 0. Hace como unos 3 años empecé desde 0 con el Vb.net sin tener pajolera idea de la que era un CommandText o un executenonquery, por citar alguna cosa.

    Me ha costado mucho y te vuelvo a repetir que sin tu ayuda quizás lo hubiera enviado a tomar aire  porque me venía grande a mi edad y a mis vida. Pero bueno, ahí se ha seguido y cada cosa que solucionaba y entendía era lo que me daba motivación para seguir.

    Lo que me sabe mal es que digas que voy dando palos de ciego, no es así Enrique, me he metido con sql y entiendo que estoy pagando la novatada hasta cierto punto, ya que con Access lo tenía todo más aprendido y cogido.

    Si es verdad, que desde que empecé hasta ahora, he ido haciendo cambios, y eso, (que tu ya no te acordarás o quizás no te ha pasado por tu experiencia) claro que he hecho cambios y los seguiré haciendo siempre que sea para mejorar el software, que me han llevado tiempo, pues sí, me han llevado tiempo y dolores de cabeza, pero hoy, creo que funciona perfectamente aunque hayan cosas que mejorar, como por ejemplo el tema que nos ha ocupado hoy.

    Bueno, ya he acabado y lamento que quizás tengas una visión distorsionada de la realidad del software este que conoces, lo lamento, pero yo creo que es muy bueno y está actualmente en una posición que es fácil de llevar y fácil de modificar, aunque lleve las 3 bases de datos.

    Bueno querido amigo, un fuerte abrazo como siempre.

    Gemma

    domingo, 9 de octubre de 2016 9:57
  • "gemma_campillo" escribió:

    > Si no dices nada al contrario, rectifico las clases de las listas y a correr.
    > Que alegría me he llevado cuando he visto los valores grabados perfectamente.

    ¡Bueno! Como parece ser que te "he asustado", voy a compensarlo con algo que quizás te produzca una alegría mayor.

    Me ha venido a la mente otro "parche" para que no tengas que convertir a String y llamar al método Replace. Para ello, tendrás que sustituir tu función Update por ésta otra implementación:

        Public Function Update() As DbCommand
    
            ' Crear el comando invariable
            Dim cmd As DbCommand = da.CreateCommand()
    
            cmd.CommandText = "UPDATE Varios " &
                              "SET Ejer_01=@p1, Ejer_02=@p2, Ejer_03=@p3, Ejer_04=@p4," &
                              "Ejer_05=@p5, Ejer_06=@p6, Ejer_07=@p7, Ejer_08=@p8, Ejer_09=@p9," &
                              "Ejer_10=@p10, Ejer_11=@p11,Ejer_12=@p12" &
                              "WHERE Cod_Empresa=@p13 And Orden=@p14"
    
            With cmd.Parameters
                .Add(da.CreateParameter("@p1", m_ejer1))
                .Add(da.CreateParameter("@p2", m_ejer2))
                .Add(da.CreateParameter("@p3", m_ejer3))
                .Add(da.CreateParameter("@p4", m_ejer4))
                .Add(da.CreateParameter("@p5", m_ejer5))
                .Add(da.CreateParameter("@p6", m_ejer6))
                .Add(da.CreateParameter("@p7", m_ejer7))
                .Add(da.CreateParameter("@p8", m_ejer8))
                .Add(da.CreateParameter("@p9", m_ejer9))
                .Add(da.CreateParameter("@p10", m_ejer10))
                .Add(da.CreateParameter("@p11", m_ejer11))
                .Add(da.CreateParameter("@p12", m_ejer12))
                .Add(da.CreateParameter("@p13", m_empresa))
                .Add(da.CreateParameter("@p14", m_orden))
            End With
    
            Return cmd
    
        End Function

    Revisa que haya escrito bien la sintaxis de la consulta UPDATE.

    Se comprende que estás haciendo uso de una variable, campo o propiedad llamada "da" a nivel global que contiene una instancia válida de la clase DataAccessInvariant.

    Esto requiere que tu clase DataAccessInvariant disponga de los siguiente métodos:

    #Region "CreateCommand"
    
        ''' <summary>
        ''' Devuelve un objeto Command apropiado al tipo de factoría creada.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CreateCommand() As DbCommand
    
            ' Crear y devolver un objeto Command.
            '
            Return m_factory.CreateCommand()
    
        End Function
    
    #End Region
    
    #Region "CreateParameter"
    
        ''' <summary>
        ''' Devuelve un objeto DbParameter apropiado al tipo de factoría creada.
        ''' </summary>
        ''' <param name="name">Nombre del parámetro.</param>
        ''' <param name="value">Valor del parámetro.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function CreateParameter(name As String, value As Object) As DbParameter
    
            ' Crear y devolver un objeto Parameter.
            '
            Dim param As DbParameter = m_factory.CreateParameter()
            param.ParameterName = name
            param.Value = value
    
            Return param
    
        End Function
    
    #End Region

    Y cuando desees actualizar la tabla de la base de datos, ejecutarías lo siguiente:

            Using cnn As DbConnection = da.CreateConnection()
    
                cnn.Open()
    
                ' Creamos el Commando
                Dim cmd As DbCommand = Update()
    
                ' Le asignamos la conexión
                cmd.Connection = cnn
    
                ' Resto del código


    Antes de cambiar los métodos Update que tengas dispersos en todas tus clases, prueba con alguno de ellos para ver si tienes problemas utilizando consultas SQL con parámetros.


    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, 9 de octubre de 2016 10:03
    Moderador
  • "gemma_campillo" escribió:

    > Lo que me sabe mal es que digas que voy dando palos de ciego, no es así Enrique, ...

    ¡Bueno! Quizás leyendo mi comentario se distorsione lo que he querido decir más que si te lo hubiera dicho en una charla personal, cara a cara, tomándonos un café o una cerveza tranquilamente. Lo mismo no te hubiera sabido tal mal. ;-)

    Que conste que yo he hecho ese comentario en base al que tu has hecho anterior:

    > Maestro, menuda leche es esto, llevo desde ayer probando y probando
    > cosas sin saber a ciencia cierta que es lo que hago.

    Cuando una persona no sabe a ciencia cierta lo que está haciendo, lo más probable es que llegue a "pegar palos de ciego" si ya no lo está dando, sin que ello suponga una ofensa, desprecio, ni nada que se parezca. Al menos, así lo pienso yo.

    Y te lo digo a ti y no a otras personas, quizás por confianza y porque personalmente conozco tu trabajo y me gustaría que las cosas que haces (a nivel de programación, obviamente) las tuvieras bien claras. Pero nada más.


    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, 9 de octubre de 2016 10:27
    Moderador
  • Hola maestro:

    Las listas genéricas con decenas de registros están funcionando perfectamente.

    Ahora quedan dispersos algunos updates que no los puedo meter en una lista porque llevan sus If, etc. y me interesa dejarlos como están.

    Voy a probar lo que me has indicado para los parámetros, pero entiendo que tampoco me están dando problemas en las 3 bases de datos, con poner simplemente ToString después de la variable:

    With cmd.Parameters
                        .Clear()
    
                        .Add(Configuracion.CreateParameter(cmd, "@ValorContable", ValorContable.ToString))
                        .Add(Configuracion.CreateParameter(cmd, "@Amortizacion", Amortizacion))
                        .Add(Configuracion.CreateParameter(cmd, "@Deterioro", Deterioro.ToString))
                        .Add(Configuracion.CreateParameter(cmd, "@ValorNeto", ValorContable.ToString + Amortizacion.ToString + Deterioro.ToString))
    

    Estos parámetros funcionan perfectamente para las 3 bases.

    Voy a ir dejando cosas listas.

    Bueno, cascarrabias un fuerte abrazo.

    Gemma

    domingo, 9 de octubre de 2016 10:43
  • "gemma_campillo" escribió:

    > Voy a probar lo que me has indicado para los parámetros, pero entiendo que
    > tampoco me están dando problemas en las 3 bases de datos, con poner simplemente
    > ToString después de la variable:

    No me refiero a que sustituyas el ToString, aunque desde luego, entiendo que está de más como te he indicado anteriormente.

    Me refiero a que sustituyas el método Update que aparece en la clase ActualizarTablaVarios_UmbralRentabilidad por el que te he indicado, para que no tengas que hacer multitud de conversiones inútiles (de Decimal, Integer, Long, etc. a String) para poder utilizar el método Replace de la clase String. Ten en cuenta que el hacer la conversión y ejecutar el método Replace también lleva su tiempo. No es que sea mucho lo que se tarde pero si hablamos de una considerable cifra de conversiones más Replace, puede que el tiempo de respuesta ya sea un poco superior.

    Aparte que considero que como se debe de trabajar es con parámetros, no con consultas SQL donde se concatenan los valores, por lo que estos serán tomados SIEMPRE como valores alfanuméricos. El String.Replace es para que puedes cambiar las posibles comas por el punto decimal, pero no quita que el valor decimal continúe siendo alfanumérico cuando en realidad debe ser el que se corresponda con el tipo de dato que tiene el campo en la tabla: Decimal, Integer, String, etc.


    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, 9 de octubre de 2016 10:51
    Moderador
  • Hola maestro:

    No te había entendido bien, ahora mismo cambio en las clases el método replace.

    Muchas gracias por preocuparte tanto.

    Un fuerte abrazo.

    Gemma

    domingo, 9 de octubre de 2016 11:01