
Editor con Access programado entre todos
#41
Escrito 26 julio 2010 - 08:28
Yo me he decantado en este caso por lo segundo, en donde la tabla notas es comparable con el encabezado de factura y las tablas Tags y Tareas serían como las líneas de detalles de dicha factura.
Por este método el usuario final tiene plena libertad de hacer cambios tanto en las tablas maestras como de detalles antes de realizar la inserción pues nada ocurrirá hasta que se pulse el botón aceptar puesto que todo esto se desarrolla en memoria, a la hora de aplicar los cambios de una modificación o de una inserción el TDatasetProvider genera las respectivas sentencias SQL las encapsula en una transacción y aplica los cambios en el orden correcto, todo esto completamente trasnparente a nosotros, por esta razón es que no nos sirven los campos autoincrementales en las tablas involucradas para este caso.
En el próximo Post explicaré la configuración de los objetos del módulo.
Saludos
Paso en el sigui
#42
Escrito 26 julio 2010 - 08:52

Primero que todo un TADoConnection que apunta a nuestra DB.
Luego un TADoQuery (qrNotas) con la sentencia:
SELECT * FROM Notas WHERE Id_Nota = -1
Esta consulta no arroja resultados porque es obvio que no hay notas con Id = -1 pero en cambio nos lleva los metadatos al otro lado del TDatasetProvider que es en realidad un puente entre el TAdoQuery y el TClientDataset.
En qrNotas creamos los campos persistentes, para esto hacemos dobleclik sobre qrNotas y cunado aparezca el editor de campos hacemos click con el boton derecho del mouse (sobre el editor de campos) y pinchamos la opción AddAllfields del popupmenu, entonces parecerá la lista con los campos de la consulta pinchamos sobre el campo Id_Nota y nos vamos al Inspector de Objetos, expandimos la opción ProviderFlags y configuramos a True la opción pfInKey, con esto le estamos diciendo al TDatasetProvider (que enlazaremos luego) que Id_Nota es la clave principal de esta tabla, para que lo pueda usar correctamente ala hora que el genera las sentencias SQL. Esta es la única configuración importante del qrNotas, aunque podrían cambiar los valores del DisplayLabel de los otros campos a su gusto, esto es opcional.
#43
Escrito 26 julio 2010 - 09:17
Luego creamos los dos querys de detalles qrTags con la sentencia:
SELECT * FROM TAGS WHERE ID_NOTA = :ID_NOTA
y qrTareas con la setencia:
SELECT * FROM TAREAS WHERE ID_NOTA = :ID_NOTA
Observe que las dos setencias en la condición WHERE apuntan a la clave foránea Id_Nota
WHERE ID_NOTA = :ID_NOTA contra un parámetro que tiene que tener obligatoriamente el mismo nombre del campo, para poder realizar correctamente la relación y ante todo las actualizaciones o inserciones. Este detalle es de suma importancia, de otro modo no funciona.
Posteriormente hacemos que tanto qrTags como qrTareas apunten su propiedad DataSource(ir al inspector de objetos) hacia la anteriormente creada dsNotas. Luego configuramos en ambos el parametro yendo al inspector de objetos y haciendo clik en el elipsisButton de la propiedad parameters, una vez aparezca el parámetro id_Nota hacemos que su propiedad DataType sea ftInteger.
Luego creamos los campos persistentes en ambos querys (qrtareas - qrTags) al igual que lo hicimos con qrNotas, una vez creados los campos persistentes en qrTags pichamos el campo Id_Tag y en el inspector de objetos expandimos ProviderFlags y ponemos a True la propiedad pfInKey, hacemos lo mismo en qrTareas con el campo Id_tarea esto con el mismo fin de decirle al TDatsetProvider cual es la clave principal de cada tabla.
Próximo post
TDatasetProvider
#44
Escrito 26 julio 2010 - 09:36
PIncFieldProps a True : Esto hace que las propiedades que configuramos anteriormente en los querys pasen automáticamente hasta el TClentDataset.
PoCascadeDeletes y poCascadeUpdates a True: Para que se generen las sentecias correctas de borrado y actualización en cascada propios de las relaciones Maestro_Detalles, configuradas previa y directamente en la Db en las relaciones.
poPropogateChanges a True : Para que se propagen los cambios que se realizan en el lado de los querys hasta el lado del TClientDataset.
PoAllowCommandText a true : Para permitir cambiar el CommandText en el lado del Tclientdataset y así permitirnos flexibilidad en las búsquedas.
Finalmente configuramos la propiedad UpdateMode a UpWhereChange para que las setencias que genera el proveedor solo incluya los campos que han cambiado, esto es importante cuando se hace en un entorno cliente servidor poque minimiza el tráfico.
Próximo post
Los TClientDataset
#45
Escrito 26 julio 2010 - 10:38
Observemos detenidamente los campos que se crearon en CdNotas, note que además de los campos de qrNotas están dos nuevos de nombres qrTareas y qrTags . Esta es la esencia de los Datasets anidados.
(Mas adelante veremos que hacemos con ellos).
Pasamos a crear en el editor de campos de cdNotas dos campos de tipo fkLookUp que nos mostraran los verdaderos valores de los campos categoria y creador, estos se llamarn RCategoria y RCreador, para hacer esto hacemos click derecho sobre el editor de campos de cdNotas y escogemos NewField del PopUpmenu, primero colocamos el nombre de Rcategoria, el tipo sera string, yel tamaño 20, escogemos la opcion Lookup en KeyField buscamos Id_categoria, en Dataset escogemos tbCategorias en LookUpKeys escogemos Id_Categoria y en ResulField Categoria, de igual manera creamos rCreador pero apuntando a tbCreadores.
Hacemos un paréntesis para echar una mirada a la función Id que ejecuta y obtiene el valor del qrGenerador a partir de su único campo(numero), puede mirar la propiedad SQL del qrGenerador, luego mediante el CommandText(cmActualizarGenerador) incrementamos el valor del unico campo de la tabla generador.
Vista esta función pasamos a configurar el evento OnNewRecord de cdNotas que apunta hacia el procedimiento GenerarId, que comparte con los TClientDataset cdTags y cdTareas, los tres TclientDataset obtienen el valor de su clave primaria mediante el procedimiento compartido GenerarId
Dataset.Fields[0].Value := id
para que cuando regresen los datos al Proveedor ya tengan estos valores para poder generar correctamente las sentencias de actualización.
Igual ocurre con el evento OnReconcileError que lo comparten los tres TClientDatasets mediante el procedimeinto ReConciliar que muestra el mensage de error en caso de que algo haya ido mal.
Solo nos resta configurar cdTags y cdTareas, observe que para estos dos no configuraremos la propiedad ProviderName como lo hicimos con CdNotas ¿Lo recuerdan? mirenlo de nuevo....
en cambio configuraremos la propiedad DatasetField de cdTags para que apunte a cdNotas.qrTags la propiedad DataSetField del cdTareas para que apunte a cdNotas.qrTareas.
Cree los campos persistentes como de costumbre, abralos y cierrelos para actualizar sus propedades, no olviden compartir los eventos OnNewRecord y OnReconcileError como lo dijimos anteriormente.
A TbCategorias y tBCreadores solo hay que configurarle la conexión, el nombre de la tabla y crear los campos persistentes.
Finalmente asegúrese de que la Con quede connected a False en tiempo de diseño.
Con esto concluimos los objetos de DataModule, luego miraremos algo de la interfaz.
#46
Escrito 27 julio 2010 - 07:28

Salud OS
#47
Escrito 27 julio 2010 - 05:07
Te molesto por una pregunta elemental pero importante para mí.
Revisando el desarrolo de tu explicación no entiendo cuando se usa los dos puntos y cuando no. Por ejemplo en estas líneas de tu desarrolo:
SELECT * FROM Notas WHERE Id_Nota = -1
SELECT * FROM TAGS
WHERE ID_NOTA = :ID_NOTA
y qrTareas con la setencia:
Código: [Seleccionar]
SELECT * FROM TAREAS
WHERE ID_NOTA = :ID_NOTA
Muchas gracias por tu generosidad
Un saludo
#48
Escrito 27 julio 2010 - 05:53
Me meto:
Primero decir que la explicacion de Wilson esta impresionante.

Ahora con la duda de esocrates:
En una sentencia SQL los dos puntos se usan antes del nombre de un parametro, estos son los que le dicen a esta sentencia que lo que viene es un parametro.
En la primera sentencia:
SELECT * FROM Notas WHERE Id_Nota = -1
Se define que el campo Id_Nota es integer por esa razon Wilson puso un numero pero tambien se podria usar un parametro, algo asi:
SELECT * FROM Notas WHERE Id_Nota = :num
Y cuando mostremos la sentencia colocaremos el parametro.
No hay regla definida de cuando usar parametros y cuando no, es una cuestion de gusto, comodidad, orden etc., depende de cada quien.
Espero que lo entiendas mejor, si no ya sabes, dilo.

Saludos
#49
Escrito 27 julio 2010 - 06:06
¡Muchas gracias! Este era uno de los problemas que tenía, porque en los tutoriales SQL que he leído no lo indicaban. Me pregunto si esto es sólo válido para Delphi, porque en "Delphi al límite" sí esta´indicado.
Un saludo
#50
Escrito 27 julio 2010 - 06:12
No amigo, es un estándar de SQL, en cualquier lenguaje entre ellos delphi.
Mira yo, tan conocedor de otros lenguajes.


Saludos
PD: Prueba de ello es que en los editores de sql es aceptado y reconocido y estos se usan para cualquier lenguaje.
#51
Escrito 27 julio 2010 - 06:19
Entiendo. La idea de los parámetros se hace clara ahora. Los ejemplos que he visto mostraban datos integer o cadenas, no parámetros. Tal vez de ahí mi confusión.Hola
No amigo, es un estándar de SQL, en cualquier lenguaje entre ellos delphi.
Mira yo, tan conocedor de otros lenguajes.![]()
Saludos
PD: Prueba de ello es que en los editores de sql es aceptado y reconocido y estos se usan para cualquier lenguaje.
Muchas gracias Caral
Nota: un favor ¿Podriás resubir tu nominas.zip.
http://www.delphiacc...hp?topic=1689.0
El archivo está corrupto
Un saludo
#52
Escrito 27 julio 2010 - 06:32
Ya actualice el programa, esta vez lo puse en el mismo hilo, no en la zona de descarga ya que no pude modificarla.
Aqui esta.
Saludos
Pd: Gracias por el aviso.
#53
Escrito 27 julio 2010 - 06:36
Hola
Ya actualice el programa, esta vez lo puse en el mismo hilo, no en la zona de descarga ya que no pude modificarla.
Aqui esta.
Saludos
Pd: Gracias por el aviso.
¡Gracias Caral! Me viene muy bien para seguir con el tema
Un saludo
#54
Escrito 27 julio 2010 - 06:44
Con relacion a los parametros:
Ya que he pasado por ese lado recomiendo el uso de los parametros en toda sentencia sql.
Esto lo notaras cuando, algun dia, quieras cambiar de access a firebird, mysql u otra BD.
Access tiene algunas manias con el sql, pero acepta el estándar por eso es mejor aprender y usar este (el estandar).
Asi si quieres cambiar tu programa a cualquier BD el cambio sera mas sencillo y rapido.
No te pegues mucho a access, tarde o temprano te convendrá usar otra BD.
Saludos
#55
Escrito 27 julio 2010 - 06:58
Te muestro de dónde ha venido mi confusión con el "Where="Hola
Con relacion a los parametros:
Ya que he pasado por ese lado recomiendo el uso de los parametros en toda sentencia sql.
Esto lo notaras cuando, algun dia, quieras cambiar de access a firebird, mysql u otra BD.
Access tiene algunas manias con el sql, pero acepta el estándar por eso es mejor aprender y usar este (el estandar).
Asi si quieres cambiar tu programa a cualquier BD el cambio sera mas sencillo y rapido.
No te pegues mucho a access, tarde o temprano te convendrá usar otra BD.
Saludos
http://www.w3schools...l/sql_where.asp
Saludos
#56
Escrito 27 julio 2010 - 07:17
Veamos el primer ejemplo de esa pagina:
This is correct:
SELECT * FROM Persons WHERE FirstName='Tove'
This is wrong:
SELECT * FROM Persons WHERE FirstName=Tove
Aqui dice lo que es correcto y lo incorrecto.
Bien:
Cuando trabajamos con un programa sea delphi u otro este tiene que hacer de enlace con la bd.
Para que el programa entienda y traduzca lo que hay en la bd.
En los programas NO es normal una sentencia como la mostrada, ya que da el nombre de la persona.
Normalmente el nombre (en este caso) se busca y para eso usamos las herramientas del programa.
Por ejemplo:
En vez de que la sentencia diga que busque todo con el nombre (Tove) usamos un edit u otro:
Concatendado:
Usamos el signo + antes del nombre del componente.
Ten en cuenta que cuando concatenamos lo hacemos en el programa, por ende no lo entendera ningun gestor de bd como sentencia correcta.
SELECT * FROM Persons WHERE FirstName = +Edit1.text;
Parametros:
Usamos los dos puntos antes del nombre del parametro (el nombre puede ser cualquiera)
SELECT * FROM Persons WHERE FirstName = :N
Como ves, el nombre lo buscara en el edit, no se lo damos directamente.
Ese es el uso de parametros o concatenacion tambien, es para que interactuemos con la bd dandole nosotros los datos a buscar.
Saludos
#57
Escrito 27 julio 2010 - 07:28
Lo voy entendiendo más ahora.Hola
Veamos el primer ejemplo de esa pagina:
This is correct:
SELECT * FROM Persons WHERE FirstName='Tove'
This is wrong:
SELECT * FROM Persons WHERE FirstName=Tove
Aqui dice lo que es correcto y lo incorrecto.
Bien:
Cuando trabajamos con un programa sea delphi u otro este tiene que hacer de enlace con la bd.
Para que el programa entienda y traduzca lo que hay en la bd.
En los programas NO es normal una sentencia como la mostrada, ya que da el nombre de la persona.
Normalmente el nombre (en este caso) se busca y para eso usamos las herramientas del programa.
Por ejemplo:
En vez de que la sentencia diga que busque todo con el nombre (Tove) usamos un edit u otro:
Concatendado:
Usamos el signo + antes del nombre del componente.
Ten en cuenta que cuando concatenamos lo hacemos en el programa, por ende no lo entendera ningun gestor de bd como sentencia correcta.
sql
SELECT * FROM Persons WHERE FirstName = +Edit1.text;
Parametros:
Usamos los dos puntos antes del nombre del parametro (el nombre puede ser cualquiera)
sql
SELECT * FROM Persons WHERE FirstName = :N
Como ves, el nombre lo buscara en el edit, no se lo damos directamente.
Ese es el uso de parametros o concatenacion tambien, es para que interactuemos con la bd dandole nosotros los datos a buscar.
Saludos
Me queda una duda sobre el concepto "parámetro"
en
SELECT * FROM Persons WHERE FirstName = :N
"N" es un campo de la tabla? como en el ejemplo de Wilson?
WHERE ID_NOTA = :ID_NOTA
Gracias una vez más
#58
Escrito 27 julio 2010 - 07:38
No amigo, N en este caso es simplemente el nombre que le di al parametro, podria haberlo llamado Caral, Maria, Pepe, N, 1a, etc.........
Traduzcamos este ejemplo a delphi:
Concatenado:
Adoquery1.sql.text:= 'SELECT * FROM Persons WHERE FirstName = '+Edit1.text; Adoquery1.Open;
Como ves Buscamos el nombre en el edit1 y abrimos la tabla
Parametros:
Adoquery1.sql.text:= 'SELECT * FROM Persons WHERE FirstName = :N'; Adoquery1.Parameters[0].Value:= Edit1.text; Adoquery1.Open;
Buscamos el nombre en el parametro, osea, el programa buscara lo que contiene el parametro, en este caso lo mismo, buscara el nombre en el edit1 ya que como ves en la linea 2 le decimos que el valor del parametro es igual al edit1.
Parece mas simple el primer ejemplo, contatenado, pero es mucho mas claro, preciso, etc el uso de parametros.
No dudes en preguntar si te quedan dudas, no se si me explico bien.
saludos
#59
Escrito 27 julio 2010 - 07:47
Lo voy a estudiar un poco.
Creo que daría para una mini aplicación de ejemplo en algún momento. Pero ya he pedido demasiado.
Caral sos un maestro
Muchísimas gracias
Saludos
#60
Escrito 27 julio 2010 - 07:54
Maestro nada, cada dia soy mas novato.

Cuando gustes abre un hilo, create una BD con una tabla o dos y le damos duro al uso de concatenacion, parametros y otras curiosidades que tiene este lenguaje.

Te insisto en el uso de parametros y creo que si no lo manejas bien deberias de entarle mucho ya que es muy Practico cuando se quiere hacer un insert, delete, update etc con sql, sobre todo cuando son muchos campos.
Me alegra servirte de algo amigo.

Saludos