gartumar2   15-11-2022, 00:47
#1
Creo que me estoy equivocando al entender que Result es un conjunto de registros obtenidos de la bdd.

Ejemplo primero y planteo la duda:

Dim rDatos as Result
rDatos = db.Find("tabla1")
rDatos.MoveFirst (ya sé que esto no es imprescindible aquí)
while rDatos.Available
       blabla(rDatos!campo1, rDatos!campo2, rDatos!campo3)
       rDatos.MoveNext
wend
 Perfecto,  funciona de mil maravillas.
Peeeero si la tabla tiene un montón de campos....... los tengo que pasar todos de uno en uno????

No he encontrado la forma de hacer blabla(rDatos.TodoElregistroDeUNgolpe) o algo que se le parezca

public sub blabla(registro As ???????what)

NI con fields, ni con ResultField, ni nada de nada.

Algo me he perdido.

Una ayudita, please.
gartumar2   15-11-2022, 07:50
#2
Auto_respuesta:
Código:
Gambas class file


Public Sub Form_Open()
    Dim db As New Connection
    Dim rDatos As Result
    Dim cRegistro As New Collection
    Dim RF As ResultField
 
    
    rDatos = db.Find("tabla1")
    
    While rDatos.Available
        cRegistro.Clear
        For Each RF In rDatos.Fields
            cRegistro.Add(rDatos[RF.name], RF.name)
        Next
        blabla(cRegistro)
        rDatos.MoveNext
    Wend
    
End


Private Sub blabla(data As Collection)
    Dim aKeys As New String[]
    Dim i As Integer
    
    Print "--------------------------------------"
    aKeys = data.Keys
    For i = 0 To aKeys.Max
        Print aKeys[i]; " - "; data[aKeys[i]]
    Next
End
Shordi   15-11-2022, 19:55
#3
Es una manera, pero si no amplías qué es lo que quieres hacer, no veo qué sentido tiene. Pasas todo a una colección, de la que luego tendrás que buscar el valor con la sintaxis:

 cCampos["nombredecampo"]

Que es la sintaxis exacta para referenciar un campo de un Result.

Si quieres pasar la colección como variable a una función, también puedes hacerlo con el result, blablabla(rs as result) sería suficiente.

Saludos
Última modificación: 15-11-2022, 19:57 por Shordi.

No podemos regresar
gartumar2   16-11-2022, 01:23
#4
Pues el tema sería algo aproximado a esto:

Imagina una bdd con mas de 30 tablas, de diversa índole, en las que unas tienen apenas dos columnas, pero otras pueden llegar a las 80 columnas. Las filas pueden llegar a ser varios miles por tabla. Esta información se procesa tanto por personas, como por diversos procesos del programa. Dependiendo de ciertos criterios unas filas serán procesadas en un sitio y otras en otros y saltaran así de proceso en proceso, recibiendo algunos cambios y acabando, según criterios en una impresora o en otra en la que imprimirá la fila completa. Por tanto no es óptimo ir repartiendo el result completo de proceso en proceso, la unidad óptima de información a manejar es la fila. Si para una tabla de 80 columnas tengo que hacer res["campo1"], res["campo2"].......res["campo80"]  Me tiro al suelo y me hago el muerto.
Además de que estamos dando por supuesto que conozco el nombre de los campos (que no) y de que no se van a añadir nuevas tablas en el futuro (cosa que con toda seguridad ocurrirá).

Por todo esto quería saber si había alguna manera de extraer un objeto registro del result, pero no se puede (o no he sabido encontrar cómo). Según medio he entendido, el result no es una colección de filas, sino mas bien, un registro de punteros a los campos de las filas y columnas de la tabla para así poder hacer temas de bloqueos, semáforos y cosas de esas raras que hacen los que saben de esto. Por todo ello, la opción de extraer la fila del result y convertirla en una colección, por ahora, me parece la ideal, aunque se comerá algunos recursos, pero no es crítico.

Gracias, por el interés. Y sigo abierto a sugerencias.
Shordi   16-11-2022, 10:44
#5
Cita:Por todo esto quería saber si había alguna manera de extraer un objeto registro del result, pero no se puede (o no he sabido encontrar cómo).
Efectivamente, no se puede... pero ¿Qué inconveniente hay en extraerlo de la BDD en cada proceso? Para eso están la BBDD precisamente... salvo que me hables de una BDD no estructurada, sin índices o de un tipo ODBC, no entiendo muy bien la lógica del asunto. ¿Sacas una selección de las tablas a una colección que pasas a distintos procesos y personas (persona = dispositivo de input-output  con 50 bits por segundo de velocidad de proceso Big Grin Big Grin ) todo en ram y luego lo vuelves a grabar todo a la BDD?
¿Qué inconveniente hay para que cada proceso o persona no pueda extraer la información precisa que necesita de la BDD?

Pero bueno, no me hagas caso, me suena que trabajas sobre algo ya muy consolidado y difícil de replantear... tú sabrás qué es lo mejor.

Saludos

Se me olvidaba. Es un obviedad, pero en los métodos de la clase Connection, tienes Exec, que pasa la consulta SQL directamente a la BDD. Suele ser más rápido y claro de leer en el código. El inconveniente respecto a Result.Find, etc. es que escribiendo

Código:
miresult = miconexion.Exec("Select * from Tabla1 where campo1 = &1", "XXX")

'o también

miconexion.Exec("Update mitabla set campo1 = &1 where campo1 = &2" ,"XXX","ZZZ")

ahorras mucho  tecleo y ganas claridad peroestás atando el código al dialecto concreto de SQL de esa BDD en concreto, con lo que tu aplicación pierde portabilidad y flexibilidad. Como programador profesional de gambas durante más de 20 años en el mundo empresarial, la experiencia me dice que las empresas raramente se lanzan a cambiar su base de datos. Si usan MySQL (o MariaBD, que es lo mismo) se mantendrán fieles a eso, si PostGreSQL pues PostGreSQL (y si Oracle... mejor no uses gambas que estarás condenado al infierno ODBC).
Por tanto, si ese es tu caso, no seas tímido con el .Exec, que facilita mucho todas las operaciones sobre las bases de datos.

Saludos.
Última modificación: 16-11-2022, 11:01 por Shordi.

No podemos regresar
tincho   16-11-2022, 11:06
#6
(16-11-2022, 01:23)gartumar2 escribió: Por tanto no es óptimo ir repartiendo el result completo de proceso en proceso, la unidad óptima de información a manejar es la fila.

Bien, he estudiado un poco el código que pasaste, es evidente que deseas minimizar las consultas a la base de datos. Si esto es correcto la forma que usas para manejar los datos del registro es correcta desde mi punto de vista (tal vez JSONCOllection sea mas conveniente que Collection).
El método COPIA tiene la desventaja de que los datos que "copias" a la colección pueden estar desfasados con respecto a los datos de la BD si alguien mas (persona o proceso) altera el mismo registro al mismo tiempo (El que guarde ultimo "pisara" los datos) o si la tabla es una tabla relacional que apunta a un registro que no existe en la base porque este fue eliminado al mismo tiempo que se trabaja con una copia.
Pero presenta la ventaja de no depender del estado de conexión con la base de datos.
Finalmente,  alteré tu mismo código para plantear la idea de como guardar los datos sirviéndose de una colección de copia para hacer la comparación.
Código:
Private cBorrador As Collection
Private sPK As String

Public Sub Form_Open()

  Dim db As New Connection
  Dim rDatos As Result
  Dim cRegistro As New Collection
  Dim RF As ResultField
  Dim rTest As Result
  Dim tb As Table
  Dim pk As String[]

  rDatos = db.Find("tabla1")
  tb = db.Tables["tabla1"]
  pk = tb.PrimaryKey
  If pk.Count > 0 Then
    sPK = pk[0]
  Else
    sPK = ""
  Endif

  While rDatos.Available
    For Each RF In rDatos.Fields
      cRegistro.Add(rDatos[RF.name], RF.name)
    Next
    blabla(cRegistro.Copy()) '' Siempre usa el método .Copy() ya que si pasas un objeto como parametro en realidad lo que esas pasando es la direccion en memoria del objeto.
    cRegistro.Clear
    rDatos.MoveNext
  Wend

End

Private Sub blabla(data As Collection)

  cBorrador = data.Copy() '' Acá creas una copia para usar luego.
  '' Acá altearás los datos en algún proceso o formulario en la colección "data" y al tener la copia contra la que comparar al momento de guardar los cambios en la BD solo en caso que estos existan. También podes alterar algún campo que uses como marca temporal o cosas así.

End

Private Function Save(data As Collection)

  Dim cCambios As New Collection
  Dim v As Variant

  If sPK <> "" Then
    cCambios.Add(data[sPK], sPK) '' Agregando el campo de la clave primaria y su valor
    For Each v In data
      If data[data.Key] <> sPK Then
        If data[data.Key] <> cBorrador[data.Key] Then
          cCambios.Add(v, data.Key)
        Endif
      Endif
    Next

    If cCambios.count > 1 Then
      Print "Los datos cambiaron"
      ''Guardar los cambios en la base de datos.
    Endif
  Endif

End

Nota: Para poner código en un mensaje seria mejor si usas el botón con el logo de gambas (el ultimo) y escribe gambas cuando aparezca la caja de dialogo.
Última modificación: 16-11-2022, 11:08 por tincho.

1 Saludo.
gartumar2   16-11-2022, 11:21
#7
Clara y razonada respuesta, gracias.

Por supuesto también uso Exec. El uso de los procesos que brinda la Connection (Find, Create, Delete, ..) los uso por comodidad (pereza de tecleo y de pensar la sentencia sql). Cuando la consulta se complica, SQL puro y duro.

La consulta sobre la extracción del registro del Result era más curiosidad de novato que otra cosa. Los que acabamos de llegar a Gambas tenemos que preguntar para aprender. Es la mejor forma.

Un saludo, grande.
Última modificación: 16-11-2022, 11:29 por gartumar2.
tincho   16-11-2022, 11:27
#8
Otro tema a tener en cuenta es el de las tablas relacionales y las claves foráneas.
Si por ejemplo tenés estas tablas:
| id | programa | licencia|
|----|---------------------------|---------|
| 1 | Gambas3 | 1 |
| 2 | Firefox | 2 |
| 3 | VirtualBox Extension Pack | 3 |
 
| id | licencia | texto |
|----|----------|-----------------------------------------------------------------|
| 1 | GPL v2 | GNU General Public License 2.1 |
| 2 | MPL | Mozilla Public License 2.0 |
| 3 | PUEL | VirtualBox Extension Pack Personal Use and Evaluation License |


¿Que valor vas a poner en el campo "licencia" de la tabla "programas"?  ¿Por ejemplo 1 o GPL v2 ?
  • Si usas "1" de todas maneras vas a tener que consultar la base de datos para saber que valor esta asociado a la clave "1".
  • Si usas "GPL v2" cuando guardes los datos tendras que convertir "GPL v2" en "1"
Última modificación: 16-11-2022, 11:31 por tincho.

1 Saludo.
gartumar2   16-11-2022, 13:09
#9
Como decía Jack El Destripador: vayamos por partes.

1) No se coman más la cabeza con esto, era más una duda existencial que un problema en sí mismo.

2)
Cita:¿Que valor vas a poner en el campo "licencia" de la tabla "programas"?  ¿Por ejemplo 1 o GPL v2 ?
  • Si usas "1" de todas maneras vas a tener que consultar la base de datos para saber que valor esta asociado a la clave "1".
  • Si usas "GPL v2" cuando guardes los datos tendras que convertir "GPL v2" en "1"

Pues para algo así, y dependiendo de lo que se necesite, lo primero que haría seria tener en la bdd una vista creada VISTAxx mas o menos así: SELECT t1.*, (SELECT t2.id as licId, t2.licencia (o texto si es lo que me interesa, o los dos) as licLic (o licTexto) FROM tabla2 t2 WHERE t1.licencia = t2.id) FROM tabla1 t1 WHERE loquesea ORDER BY loquesea;
Crearía el result con SELECT * FROM VISTAxx WHERE loquenecesite; (el order by ya lo hace la vista) y en cada registro tengo los campos de la tabla 1 y los asociados de la tabla 2. Cuando tengo que grabar tengo todo disponible y a mano. Para modificaciones, pues si las necesidades del proceso lo permiten, le paso el marrón a la bdd con RESTRICT, CASCADE, o lo que convenga.

Saludos, de nuevo.
Última modificación: 16-11-2022, 13:36 por gartumar2.
  
Usuarios navegando en este tema: 2 invitado(s)
Powered By MyBB, © 2002-2024 MyBB Group.
Made with by Curves UI.