none
Error en creación de Lista genérica para consultas de selección.

    Pregunta

  • Hola a todos.

    Precisaría poder crear correctamente una lista que me recoja las consultas de selección que casi siempre son las mismas y en las que varía únicamente el condicional Where y su item Cód_CG que puede ser de 1 item o varios items.

    La consulta de ejemplo podría ser como esta, la tengo acotada para no hacerla larga.

     Public Shared Sub Formula_OtrosGastos()
            Try
                'Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
                Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
                Dim valor As Integer = AccesoLogica.ObtenerPeriodos()
                Dim i As Integer
    
                ' Declaramos una variable Connection
                Using cnn As DbConnection = da.CreateConnection()
    
                    ' Creamos el Commando
                    Dim cmd As DbCommand = cnn.CreateCommand
    
                    ReDim OtrosGastos(OtrosGastos.Length - 1)
    
                    If VarGlobal.StrCodPais = "34" Then
                        If VarGlobal.StrPlanConta = "PLAN 2007" Then
                            cmd.CommandText = "SELECT Ejer_01, Ejer_02, Ejer_03, Ejer_04, Ejer_05, Ejer_06, Ejer_07, Ejer_08, Ejer_09, Ejer_10, Ejer_11, Ejer_12  " &
                                        "FROM Balances WHERE IdEmpresa = @empresa AND PlanConta = 'PLAN 2007'  " &
                                        "AND Cód_GC IN ('651','6510','6511','659')"
    
          end if
      nd If
    
                    'Creamos el parametro
                    cmd.Parameters.Add(Configuracion.CreateParameter(cmd, "@empresa", VarGlobal.StrCodEmpresa))
    
                    ' Asignamos la conexión al comando
                    cmd.Connection = cnn
                    cnn.Open()
    
                    Using dr As DbDataReader = cmd.ExecuteReader()
                        While dr.Read
                            For i = 0 To valor
                                OtrosGastos(i) += dr.GetDecimal(i)
                            Next
                        End While
                    End Using
    
                End Using
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: '3624'" & vbCrLf & ex.Message & vbCrLf &
                   "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub 'ok

    y en la cual, calculo el valor de la propiedad " OtrosGastos(i) " que es un array de 12 posiciones. (0 to 11).

    Hecho esto, he creado una clase para la lista de selección con el fin de evitar tener tantas selects como la del ejemplo y con ello ahorrar líneas de código ya que en las mismas solo cambiarán muy pocas propiedades.

    La clase lista la he creado así:

    Friend Class SeleccionDatos
    
        ' Declarar la clase como Friend si solo se va a utilizar desde procedimientos
        ' existentes en el mismo ensamblado.
    
        Private m_empresa As String
        Private m_planconta As String
        Private m_ejer01 As Decimal
        Private m_ejer02 As Decimal
        Private m_ejer03 As Decimal
        Private m_ejer04 As Decimal
        Private m_ejer05 As Decimal
        Private m_ejer06 As Decimal
        Private m_ejer07 As Decimal
        Private m_ejer08 As Decimal
        Private m_ejer09 As Decimal
        Private m_ejer10 As Decimal
        Private m_ejer11 As Decimal
        Private m_ejer12 As Decimal
        Private m_codigo As String
    
        Public Sub New(ejer01 As Decimal, ejer02 As Decimal, ejer03 As Decimal, ejer04 As Decimal, ejer05 As Decimal, ejer06 As Decimal,
                       ejer07 As Decimal, ejer08 As Decimal, ejer09 As Decimal, ejer10 As Decimal, ejer11 As Decimal, ejer12 As Decimal, empresa As String, planconta As String, codigo As String)
            m_empresa = empresa
            m_planconta = planconta
            m_codigo = codigo
            m_ejer01 = ejer01
            m_ejer02 = ejer02
            m_ejer03 = ejer03
            m_ejer04 = ejer04
            m_ejer05 = ejer05
            m_ejer06 = ejer06
            m_ejer07 = ejer07
            m_ejer08 = ejer08
            m_ejer09 = ejer09
            m_ejer10 = ejer10
            m_ejer11 = ejer11
            m_ejer12 = ejer12
    
        End Sub
    
        Public ReadOnly Property empresa As String
                Get
                    Return m_empresa
                End Get
            End Property
    
        Public ReadOnly Property planconta As String
            Get
                Return m_planconta
            End Get
        End Property
    
        Public ReadOnly Property codigo As String
            Get
                Return m_codigo
            End Get
        End Property
    
        Public ReadOnly Property ejer01 As Decimal
            Get
                Return m_ejer01
            End Get
        End Property
    
        Public ReadOnly Property ejer02 As Decimal
                Get
                    Return m_ejer02
                End Get
            End Property
    
            Public ReadOnly Property ejer03 As Decimal
                Get
                    Return m_ejer03
                End Get
            End Property
    
            Public ReadOnly Property ejer04 As Decimal
                Get
                    Return m_ejer04
                End Get
            End Property
    
            Public ReadOnly Property ejer05 As Decimal
                Get
                    Return m_ejer05
                End Get
            End Property
    
            Public ReadOnly Property ejer06 As Decimal
                Get
                    Return m_ejer06
                End Get
            End Property
    
            Public ReadOnly Property ejer07 As Decimal
                Get
                    Return m_ejer07
                End Get
            End Property
    
            Public ReadOnly Property ejer08 As Decimal
                Get
                    Return m_ejer08
                End Get
            End Property
    
            Public ReadOnly Property ejer09 As Decimal
                Get
                    Return m_ejer09
                End Get
            End Property
    
            Public ReadOnly Property ejer10 As Decimal
                Get
                    Return m_ejer10
                End Get
            End Property
    
            Public ReadOnly Property ejer11 As Decimal
                Get
                    Return m_ejer11
                End Get
            End Property
    
            Public ReadOnly Property ejer12 As Decimal
                Get
                    Return m_ejer12
                End Get
            End Property
    
            Public Overrides Function ToString() As String
    
            ' Devolver una cadena 
            Return String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, '{12}', '{13}', '{14}'",
                                  m_ejer01, m_ejer02, m_ejer03, m_ejer04, m_ejer05, m_ejer06, m_ejer07, m_ejer08, m_ejer09,
                                  m_ejer10, m_ejer11, m_ejer12, m_empresa, m_planconta, m_codigo)
    
        End Function
    
        End Class
    

    Y la lista en sí y es ahí donde tengo problemas al no tener claro como construirla para albergar los datos que iré necesitando de las selects.

     Public Shared Sub ListOF_Formulas_Select()
            Try
                Dim lst As New List(Of SeleccionDatos)
                Dim empresa As String = VarGlobal.StrCodEmpresa
                Dim planconta As String = VarGlobal.StrPlanConta
    
                If VarGlobal.StrCodPais = "34" Then
                    If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
    
                        lst.Add(New SeleccionDatos(OtrosGastos(0), OtrosGastos(1), OtrosGastos(2), OtrosGastos(3), OtrosGastos(4), OtrosGastos(5), OtrosGastos(6), OtrosGastos(7), OtrosGastos(8), OtrosGastos(9), OtrosGastos(10), OtrosGastos(11), empresa, planconta, "IN ('651','6510','6511','659')"))
    
                        ' Creamos el acceso a datos mediante el nombre de la cadena de conexión existente en el archivo de configuración de la aplicación.
                        Dim da As DataAccessInvariant = DataAccessInvariant.GetDataAccessInvariant(Configuracion.CadenaConexion)
    
                        Using cnn As DbConnection = da.CreateConnection()
    
                            For Each item As SeleccionDatos In lst
    
                                ' Creamos el Commando
                                Dim cmd As DbCommand = cnn.CreateCommand()
                                cmd.CommandText = item.ToString
    
                                cmd.CommandText = String.Format("SELECT 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} " &
                                        "FROM Balances WHERE IdEmpresa ='{12}' AND PlanConta ='{13}' AND Cód_GC='{14}) VALUES ({0})", item.ToString())
    
                                ' Asignamos la conexión al comando
                                cmd.Connection = cnn
                                cnn.Open()
                            Next
    
                        End Using
                    End If
                End If
    
            Catch ex As Exception
                MessageBox.Show("Bloqueo en carga de Fórmula: 'ListasOF Selección Datos'" & vbCrLf & ex.Message & vbCrLf &
                        "Acepte para continuar.", "FINANCIAL SYSTEM", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub

    En esta última sentencia es donde no me aclaro por mas que la pruebo nunca lleva datos y da un error : "El índice basado en 0, debe ser mayor o igual a 0 y menor que el índice de la lista de argumentos.

    En fin, que no se meter la select inicial para que funcione en una lista y olvidarme de ellas.

    Un cordial saludo a todos.

    Gemma

    martes, 22 de noviembre de 2016 15:02

Respuestas

  • gemma_campillo,

    No necesitas iterar por la lista, basta pasar los argumentos contenidos en la lista como un array.

    Por otro lado, creo que la consulta no es correcta,

    ¿la instrucción VALUES dentro de una consulta de selección?

    Si el argumento 14 es una cadena que contiene una expresión IN() no debe estar precedida por el operador =

    Using cnn As DbConnection = da.CreateConnection()
    
    	' Creamos el Commando
    	Dim cmd As DbCommand = cnn.CreateCommand()
    	cmd.CommandText = item.ToString
    
    	cmd.CommandText = String.Format("SELECT Ejer_01={0}, Ejer_02={1}, ... " &
    	"FROM Balances WHERE IdEmpresa ='{12}' AND PlanConta ='{13}' AND Cód_GC '{14}", lst.ToArray())
    
    	' Asignamos la conexión al comando
    	cmd.Connection = cnn
    	cnn.Open()
    
    End Using


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 17:49
    martes, 22 de noviembre de 2016 17:31
  • gemma_campillo,

    Si la lista de columnas es la misma no encuentro razón para contenerla en una colección, la parte que es variable deberías interpolarla, pienso que no hay necesidad de agregar complejidad al código y con ello restar en legibilidad. La clase que has creado tampoco le veo sentido, sobre el caso que presentas -y dándote al gusto de contenerlo en una colección- yo haría lo siguiente:

    If VarGlobal.StrCodPais = "34" Then
    	If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
    
    		Dim Argumentos As String() =
    		{
    			OtrosGastos(0), OtrosGastos(1), OtrosGastos(2), OtrosGastos(3), OtrosGastos(4),
    			OtrosGastos(5), OtrosGastos(6), OtrosGastos(7), OtrosGastos(8), OtrosGastos(9),
    			OtrosGastos(10), OtrosGastos(11),
    			empresa, planconta, "IN ('651','6510','6511','659')"
    		}
    
    		' Creamos el acceso a datos mediante ...
    		Dim da As DataAccessInvariant = DataAccessInvariant...
    
    		Using cnn As DbConnection = da.CreateConnection()
    			' Creamos el Commando
    			Dim cmd As DbCommand = cnn.CreateCommand()
    			cmd.CommandText = item.ToString
    
    			cmd.CommandText = String.Format("SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, " &
    			"{7}, {8}, {9}, {10}, {11} FROM Balances WHERE IdEmpresa ='{12}' " &
    			"And PlanConta ='{13}' And Cód_GC '{14}", Argumentos)
    
    			' Asignamos la conexión al comando
    			cmd.Connection = cnn
    			cnn.Open()
    		End Using
    	End If
    End If

    Intenta realizar los cambios tal como lo adjunto y coméntanos como te fue.


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.

    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 18:41
    martes, 22 de noviembre de 2016 18:34
  • gemma_campillo,

    Lo lamento, no me da el tiempo para  revisar todo el código que adjuntas pero tenía supuesto que la variable OtrosGastos contenía el nombre de todas las columna que deseas mostrar en la lista de selección, al ser un tipo 'Decimal' queda claro que obtendrás la excepción que comentas. 

    Por lo que comentas ya no me queda claro porque asignas un valor en la consulta de selección cuando el valor lo debes de obtener a través de la propia consulta, los primeros 11 argumentos deberían ser los nombres de las columnas:

    Dim Argumentos As String() =
            {
                "Ejer_01", "Ejer_02", "Ejer_03", "Ejer_04", "Ejer_05", "Ejer_06", 
                "Ejer_07", "Ejer_08", "Ejer_09", "Ejer_10", "Ejer_11", "Ejer_12",
                empresa, planconta, "IN ('651','6510','6511','659')"
            }

    Respecto a la variable 'Item' ya no se usa para el ejemplo propuesto.

    En caso las soluciones que te estoy proponiendo no tengan que ver con el objetivo que esperas te agradeceré me lo hagas saber, vuelvo a colocar el código actualizado:

    If VarGlobal.StrCodPais = "34" Then
    	If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
    
    		Dim Argumentos As String() =
            {
                "Ejer_01", "Ejer_02", "Ejer_03", "Ejer_04", "Ejer_05", "Ejer_06", 
                "Ejer_07", "Ejer_08", "Ejer_09", "Ejer_10", "Ejer_11", "Ejer_12",
                empresa, planconta, "IN ('651','6510','6511','659')"
            }
    
    		' Creamos el acceso a datos mediante ...
    		Dim da As DataAccessInvariant = DataAccessInvariant...
    
    		Using cnn As DbConnection = da.CreateConnection()
    			' Creamos el Commando
    			Dim cmd As DbCommand = cnn.CreateCommand()
    			cmd.CommandText = item.ToString
    
    			cmd.CommandText = String.Format("SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, " &
    			"{7}, {8}, {9}, {10}, {11} FROM Balances WHERE IdEmpresa ='{12}' " &
    			"And PlanConta ='{13}' And Cód_GC '{14}", Argumentos)
    
    			' Asignamos la conexión al comando
    			cmd.Connection = cnn
    			cnn.Open()
    		End Using
    	End If
    End If



    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 19:03
    martes, 22 de noviembre de 2016 18:56

Todas las respuestas

  • gemma_campillo,

    No necesitas iterar por la lista, basta pasar los argumentos contenidos en la lista como un array.

    Por otro lado, creo que la consulta no es correcta,

    ¿la instrucción VALUES dentro de una consulta de selección?

    Si el argumento 14 es una cadena que contiene una expresión IN() no debe estar precedida por el operador =

    Using cnn As DbConnection = da.CreateConnection()
    
    	' Creamos el Commando
    	Dim cmd As DbCommand = cnn.CreateCommand()
    	cmd.CommandText = item.ToString
    
    	cmd.CommandText = String.Format("SELECT Ejer_01={0}, Ejer_02={1}, ... " &
    	"FROM Balances WHERE IdEmpresa ='{12}' AND PlanConta ='{13}' AND Cód_GC '{14}", lst.ToArray())
    
    	' Asignamos la conexión al comando
    	cmd.Connection = cnn
    	cnn.Open()
    
    End Using


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 17:49
    martes, 22 de noviembre de 2016 17:31
  • Hola querido Williams:

    Me está volviendo loca la maldita lista, bueno, he hecho lo que me has dicho pero continúa dándome el error: "El índice basado en 0, debe ser mayor o igual a 0 y menor que el índice de la lista de argumentos. De cualquier forma voy a repasarla de arriba a abajo, pero seguro que tu respuesta es correcta.

    Si hay alguna cosa te la comunicaré.

    Muchas gracias querido amigo como siempre, pero quiero sacarla bien, porque me ahorrará muchísimo código con las select que son casi iguales.

    Un abrazo.

    Gemma

    martes, 22 de noviembre de 2016 17:49
  • gemma_campillo,

    Si la lista de columnas es la misma no encuentro razón para contenerla en una colección, la parte que es variable deberías interpolarla, pienso que no hay necesidad de agregar complejidad al código y con ello restar en legibilidad. La clase que has creado tampoco le veo sentido, sobre el caso que presentas -y dándote al gusto de contenerlo en una colección- yo haría lo siguiente:

    If VarGlobal.StrCodPais = "34" Then
    	If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
    
    		Dim Argumentos As String() =
    		{
    			OtrosGastos(0), OtrosGastos(1), OtrosGastos(2), OtrosGastos(3), OtrosGastos(4),
    			OtrosGastos(5), OtrosGastos(6), OtrosGastos(7), OtrosGastos(8), OtrosGastos(9),
    			OtrosGastos(10), OtrosGastos(11),
    			empresa, planconta, "IN ('651','6510','6511','659')"
    		}
    
    		' Creamos el acceso a datos mediante ...
    		Dim da As DataAccessInvariant = DataAccessInvariant...
    
    		Using cnn As DbConnection = da.CreateConnection()
    			' Creamos el Commando
    			Dim cmd As DbCommand = cnn.CreateCommand()
    			cmd.CommandText = item.ToString
    
    			cmd.CommandText = String.Format("SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, " &
    			"{7}, {8}, {9}, {10}, {11} FROM Balances WHERE IdEmpresa ='{12}' " &
    			"And PlanConta ='{13}' And Cód_GC '{14}", Argumentos)
    
    			' Asignamos la conexión al comando
    			cmd.Connection = cnn
    			cnn.Open()
    		End Using
    	End If
    End If

    Intenta realizar los cambios tal como lo adjunto y coméntanos como te fue.


    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.

    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 18:41
    martes, 22 de noviembre de 2016 18:34
  • Hola Williams:

    Me da error indicándome :

    Option Strict On no permite conversiones implícitas de 'Decimal' a 'String'. Eso lo da en: Dim Argumentos As String() =
    {
    OtrosGastos
    (0), OtrosGastos(1), OtrosGastos(2), OtrosGastos(3), OtrosGastos(4),
    OtrosGastos
    (5), OtrosGastos(6), OtrosGastos(7), OtrosGastos(8), OtrosGastos(9),
    OtrosGastos
    (10), OtrosGastos(11),
    empresa
    , planconta, "IN ('651','6510','6511','659')"
    }

    Y después que Item no está declarado, claro, le hemos sacado el ForEach.

    Bueno, a ver si tenemos suerte.

    Muchas gracias querido amigo.

    Gemma

    martes, 22 de noviembre de 2016 18:41
  • gemma_campillo,

    Lo lamento, no me da el tiempo para  revisar todo el código que adjuntas pero tenía supuesto que la variable OtrosGastos contenía el nombre de todas las columna que deseas mostrar en la lista de selección, al ser un tipo 'Decimal' queda claro que obtendrás la excepción que comentas. 

    Por lo que comentas ya no me queda claro porque asignas un valor en la consulta de selección cuando el valor lo debes de obtener a través de la propia consulta, los primeros 11 argumentos deberían ser los nombres de las columnas:

    Dim Argumentos As String() =
            {
                "Ejer_01", "Ejer_02", "Ejer_03", "Ejer_04", "Ejer_05", "Ejer_06", 
                "Ejer_07", "Ejer_08", "Ejer_09", "Ejer_10", "Ejer_11", "Ejer_12",
                empresa, planconta, "IN ('651','6510','6511','659')"
            }

    Respecto a la variable 'Item' ya no se usa para el ejemplo propuesto.

    En caso las soluciones que te estoy proponiendo no tengan que ver con el objetivo que esperas te agradeceré me lo hagas saber, vuelvo a colocar el código actualizado:

    If VarGlobal.StrCodPais = "34" Then
    	If VarGlobal.StrPlanConta = "PLAN 2007" OrElse VarGlobal.StrPlanConta = "FISCAL" Then
    
    		Dim Argumentos As String() =
            {
                "Ejer_01", "Ejer_02", "Ejer_03", "Ejer_04", "Ejer_05", "Ejer_06", 
                "Ejer_07", "Ejer_08", "Ejer_09", "Ejer_10", "Ejer_11", "Ejer_12",
                empresa, planconta, "IN ('651','6510','6511','659')"
            }
    
    		' Creamos el acceso a datos mediante ...
    		Dim da As DataAccessInvariant = DataAccessInvariant...
    
    		Using cnn As DbConnection = da.CreateConnection()
    			' Creamos el Commando
    			Dim cmd As DbCommand = cnn.CreateCommand()
    			cmd.CommandText = item.ToString
    
    			cmd.CommandText = String.Format("SELECT {0}, {1}, {2}, {3}, {4}, {5}, {6}, " &
    			"{7}, {8}, {9}, {10}, {11} FROM Balances WHERE IdEmpresa ='{12}' " &
    			"And PlanConta ='{13}' And Cód_GC '{14}", Argumentos)
    
    			' Asignamos la conexión al comando
    			cmd.Connection = cnn
    			cnn.Open()
    		End Using
    	End If
    End If



    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta gemma_campillo martes, 22 de noviembre de 2016 19:03
    martes, 22 de noviembre de 2016 18:56
  • Hola:

    Venga, me pongo a ello a ver si lo saco.

    Te digo alguna cosa y muchas gracias como siempre.

    Gemma

    martes, 22 de noviembre de 2016 19:03