Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Componente para guardar el valor estable de BD (https://www.clubdelphi.com/foros/showthread.php?t=50872)

Garry 30-11-2007 11:40:16

Componente para guardar el valor estable de BD
 
Hola, viejos

Soy nuevo (en Delphi y en el foro) y no sé si estoy usando el procedimiento adecuado al iniciar este hilo; pero, si es el caso, ya me corregiréis :p

Estoy creando un componente basado en DBEdit para conservar el último valor estable de la BD (tras consultar/grabar, "garantía" de que aún se tiene un valor actualizado). Para ello, añado una propiedad "OldText" cuyo valor podrá ser cotejado con el que actualmente haya en edición.

:confused: El caso es: ignoro cómo hacer que dicho valor se actualice desde el propio componente en el momento de la consulta. Así, podría ahorrar tener que invocar a un método por cada campo de cada formulario con cada botón que acceda a la BD.

No sé si me he explicado bien... Gracias por vuestro tiempo y un abrazo

Lepe 30-11-2007 14:42:01

Esto no lo entiendo:
Cita:

Empezado por Garry
para conservar el último valor estable de la BD (tras consultar/grabar, "garantía" de que aún se tiene un valor actualizado)

¿quieres que después de guardar un registro, aún conserve el valor anterior?

El TDBEdit tiene un procedimiento protegido llamado Change, si estas heredando de dicho componente, puedes redefinir (gracias Al González) su comportamiento con la directiva override y copiar el texto antes de cambiarlo.

Como digo, no comprendo la situación en que quieres hacer eso. Existe la posibilidad de trabajar con Cache Updates, de forma que el usuario puede hacer un post de un registro, pero que no se grabe directamente a la Base de datos, estos cambios pueden afectar a varias tablas sin problemas.

Al realizar un ApplyUpdates de los dataset, es cuando tienes oportunidad de grabar los cambios o volver al estado anterior.

Saludos

Garry 05-12-2007 13:31:23

Perdón por tardar tanto en responder...
 
Cita:

Empezado por Lepe (Mensaje 249593)
¿quieres que después de guardar un registro, aún conserve el valor anterior?

No sólo después de guardar, sino cada vez que en el componente haya un "valor estable": tengo botones Guardar, Limpiar y Consultar, tras cuyas pulsaciones hay lo que llamo "valor estable" porque los campos aún no han sido editados: o se parte de valores vacíos (botón Guardar), o de valores actualizados (los otros botones).

Heredo del TDBEdit, sí, pero entiendo que no me sirve el evento Change porque sólo toma el valor inicial antes de empezar a editar por primera vez, no ayudando a conservar el original en ediciones sucesivas del campo.

Quiero que el componente conserve automáticamente lo que había cargado (valor vacío o valor de BD). Esto sirve, por ejemplo, para decir al usuario algo como: "Todavía no has grabado, ¿seguro que quieres consultar?".
Espero haberme explicado mejor, no sé si queda claro :confused:

Lo de Cache Updates suena interesante (ya lo estudiaré), pero no para ahora porque me parece que sólo vale para postergar la grabación. Y, como intentaba aclarar, pretendo conservar el dato consultado inicialmente para evitar tener que volver a consultarlo.

Por cierto, gracias, Lepe, aunque todavía no lo haya resuelto. Un saludiño desde Coruña...

Garry 05-12-2007 13:35:30

Corrección
 
Cita:

Empezado por Garry (Mensaje 250548)
...o se parte de valores vacíos (botón Guardar)...

Perdón... quería decir botón Limpiar

Garry 11-12-2007 13:32:53

Voy a simplificar un poco
 
Lo que pretendo, por ahora, es que cada campo consultado guarde automáticamente el valor cargado en una nueva propiedad (OldText) de mi nuevo componente (TGDBEdit).

Tras Consultar y Guardar, se actualiza dicha propiedad con lo cargado; al Limpiar se actualiza con el valor vacío.

Hasta luego y gracias de nuevo por la ayuda...

Lepe 11-12-2007 14:33:58

Perdón por tardar en contestar, al parecer se me ha perdido este hilo.

¿Acaso no hace eso ya los controles?

Si estoy editando un registro y quiero volver al valor anterior, uso Dataset.Cancel y esto volverá el registro al último valor estable.

Si doy a guardar (Dataset.Post), el nuevo valor pasa al valor del campo y el viejo se pierde.

El botón Limpiar, correspondería a la acción Dataset.Insert que traerá los valores por defecto de cada campo (establecidos en la base de datos como valores por defecto) y asignará sus valores a los DBEdits.

Para saber si un campo ha sido modificado en el DBEdit, tienes la propiedad Modified del TField.

Creo que verías más claro el asunto usando un TDBNavigator, porque te deja cancelar los cambios y volver a lo que tu llamas "valores estables".

Edito: El botón consultar tendría este código:
Código Delphi [-]
Msg := EmptyStr;

if Dataset in EditModes then // posiblemente ha sido modificado la edición
 for i:= 0 to dataset.Fields.Count -1 do
   if dataset.Fields[i].Modified then
     Msg:= msg + '- '+ dataset.fields[i].FieldName + #10#13;

  if Msg <> EmptyStr then 
  begin 
    Msg := 'Los siguientes campos han sido modificados:'+ #10#13 + Msg + ' ¿desea descartar los cambios realizados?';
    if Application.Messagebox(msg, 'Advertencia', mbyesno) = idyes then
    begin
      Dataset.Cancel;
      // consultar
    end
    else  // no hacer nada, el registro quedará en edición con los cambios realizados, dando
         // la posibilidad de guardar o cancelar.
end;

Si expongo todo esto, es porque dices que eres "nuevo en delphi" y puedes estar reinventando la rueda.

Saludos

egostar 11-12-2007 18:38:37

Cita:

Empezado por Lepe (Mensaje 251757)
Si expongo todo esto, es porque dices que eres "nuevo en delphi" y puedes estar reinventando la rueda.

Vaya, a veces me asombro de otros compañeros, yo me digo no ser tan novato en esto de Delphi, pero nunca, si señor como lo leen, nunca he tenido la inteligencia o dedicación de aprender a crear un componente, alguna vez lo intente y acabe frustrado, no pude :(

Mejor no intento reinventar la rueda, :)

Salud OS

Garry 11-12-2007 20:06:07

Como decía, novato... e ingenuo
 
Ya, egostar, pero es un intento, tal y como dices :). Quizá es que empiezo por poner el carro delante de los bueyes y comienzo a lo suicida... En mi feliz ignorancia y por poner un ejemplo, se me ocurre recomendarte este curso de creación de componentes para iniciarte (todo es cuestión de empezar por algún sitio). Confieso que todo esto se me antoja bastante complicadillo...

El caso es que lo que me aporta Lepe me viene muy bien porque ya reconocí ser novatillo, así que agradezco mucho las ayudas, jeje. De todos modos, tendré que probarlo porque lo que quiero es detectar sólo cambios útiles para descartar actualizaciones en las que se "descambie" el contenido. El objetivo es evitar ir a la base de datos innecesariamente y no sé si esa propiedad que cuentas sirve porque:
  1. Cargo el valor a.
  2. Edito y pongo b (...Modified = true).
  3. Reedito "descambiando", quedando nuevamente a (si ahora ...Modified = true? no serviría).
Realmente, también quería reinventar el fuego :p y que el cambio lo detecte el propio componente internamente tras cada edición, para colorear cuando haya cambios y/o errores, actualizar el filtro de búsqueda sin tener que contorlar todos los cambios uno a uno...

Lepe 11-12-2007 21:22:43

Cita:

Empezado por Garry (Mensaje 251865)
  1. Cargo el valor a.
  2. Edito y pongo b (...Modified = true).
  3. Reedito "descambiando", quedando nuevamente a (si ahora ...Modified = true? no serviría).

en 3, no estas reeditando, porque no has guardado aún. tampoco hay valor "estable".

El valor antiguo será "a". si usas Dataset.cancel es como si no hubieras hecho nada. si usas Dataset.Post estarás actualizando un registro con los mismos valores que tenías antes. Entiendo que es lo que quieres evitar, pero sigue leyendo.

El punto aquí, sería poner una webcam, para ver el usuario cuantas veces entra y sale de un DBEdit cambiando los valores, y adivinar cual de todas esas modificaciones, considera "estable". Una letra de más, una tilde, un espacio... y todos nuestros esfuerzos por la borda.

Si un usuario hace esos 3 pasos que has indicado, yo le explico cuando debe hacer un Post y cuando un Cancel .

Como en muchas ocasiones, el problema está entre el teclado y la silla ;).

Saludos

Lepe 11-12-2007 21:23:39

ha salido repe el mensaje...

Saludos

Garry 13-12-2007 11:35:45

Quizá sí, quizá no...
 
Cita:

Empezado por Lepe (Mensaje 251899)
...y adivinar cual de todas esas modificaciones, considera "estable". Una letra de más, una tilde, un espacio... y todos nuestros esfuerzos por la borda.

Tienes algo de razón, Lepe (aunque esto ronda la metafísica). No obstante, no es necesario entrar en ese debate, ya que cada uno tiene sus motivos. Cualquier cosa que retoque el usuario merece la consideración oportuna según cada caso.

En el mío, pretendo eliminar tabulaciones y espacios indeseados, autocorregir la capitalización, y comparar ese valor formateado con el original para reducir aún más los accesos a la BD, con lo que debo comparar los valores yo mismo.

Vale, puedo ser un poco maniático (quizá soy informático por ello, no sé, :D), pero me parece que lo interesante sigue sin respuesta:
Cita:

¿Hay cómo recuperar el valor original sin crear un nuevo componente?
Tal vez todo el hilo se reduce a esto y quizá rayo en lo inútil, pero no deja de ser la duda que planteo. Aunque puede no parecer útil para la actualización, sí aún para lo que decía de los colores, por ejemplo.

De todas formas, el código que me diste me va a ser muy útil, claro. No daría por zanjada la cuestión ;), pero gracias por la sugerencia.

Lepe 13-12-2007 12:13:50

El DBEdit es una mera representación visual. Si quieres capturar cuando cambian los datos, antes de que los valores vayan a parar a la base de datos, o al recibirlos, tendrás que pelearte con el TFieldDataLink. Dicha clase tiene:
Código Delphi [-]
protected
    procedure ActiveChanged; override;
    procedure DataEvent(Event: TDataEvent; Info: Integer); override;
    procedure EditingChanged; override;
    procedure FocusControl(Field: TFieldRef); override;
    procedure LayoutChanged; override;
    procedure RecordChanged(Field: TField); override;
    procedure UpdateData; override;
public
    property OnDataChange: TNotifyEvent read FOnDataChange write FOnDataChange;
    property OnEditingChange: TNotifyEvent read FOnEditingChange write FOnEditingChange;
    property OnUpdateData: TNotifyEvent read FOnUpdateData write FOnUpdateData;
    property OnActiveChange: TNotifyEvent read FOnActiveChange write FOnActiveChange;

Los métodos protegidos serán los que tienes que modificar. Aparte, tendrías que crearte un nuevo TDBEdit que use tu TFieldDatalink modificado.

Espero me equivoque y haya un método más fácil. Pero dudo que sea trabajando sobre el TDBEdit, porque te dará falsos positivos (por ejemplo, al cambiar de registro, se producirá un evento DBedit.OnChange y "no podrías diferenciarlo de cuando el usuario modifica el registro" (este caso es un mero ejemplo, no lo tomes al pie de la letra, porque no he estudiado el caso a fondo).

En respuesta a tu pregunta directa:
Si, si lo hay, en el evento afterScroll de tu Dataset, pero no será viable hacerlo allí.

Saludos

Garry 13-12-2007 13:11:26

¡Bufff!
 
Creo que esto me supera con creces.

Y tienes razón con el DBedit.OnChange, lo había probado y salta al cargar valores, ¡rayos! Mi gozo en un pozo. Al menos, de momento. Supongo que ya volveré sobre esto, pero así me va costar demasiado avanzar...

Me pregunto si alguien se ha currado algo similar que pueda y quiera aportar alguna idea. Creo que sería un componente útil para todo en esta vida, jeje.

Un saludillo y gracias por responder tan rápidamente ;).

Lepe 13-12-2007 15:10:53

Te voy a contar un secreto que espero sepas guardar :D :D.

A veces, en lugar de heredar de TDBEdit, lo que hago es crear mis propios objetos, mapeando los datos a ellos cuando lo necesito. Ejemplo simplificado:
Código Delphi [-]
type TMiRegistro = class(TObject);

public
   constructor Create; override;
   Valores:TStrings
end;

implementation

constructor TMiRegistro.Create;
begin
  Valores := TStringList.Create;
end;
Ahora en mi aplicación, en el OnCreate de la ventana Clientes (típico tópico donde los haya:p):
Código Delphi [-]
private
 Actual :TMiRegistro; // declarado arriba, en el Form


procedure TForm1.FormCreate....
begin
   Actual := TMiRegistro.Create;
end;

procedure TForm1.TablaclienteAfterScroll;
begin
  Actual.Valores.Clear; // borramos los valores del registro anterior
   for i:= 0 to tablaClientes.FieldCount -1 do
     Actual.Valores.Add(tablaClientes.Fields[i].AsString);
end;

procedure TForm1.Close(...);
begin 
  Actual.Free;
end;
Nada del otro mundo, Simplemente guardar los valores en el AfterScroll y cuando quiera sobreescibir alguno con un "valor estable", modifico mi objeto.

Saludos

Garry 17-12-2007 12:37:53

Gracias, Lepe.

Bueno, sin afán de restar méritos, se aproxima a cómo pensaba yo solucionar en plan "simple", es decir, renunciando a la automatización que deseaba para cada campo (al tener que centralizar el control campo a campo en un mismo punto y despreciando la comodidad de los DBEdit). Como consuelo, veo que no voy tan desencaminado ;)

Ya volveré sobre esto y, si consigo algún avance interesante, ya lo contaré. Ahora necesito progresar con el desarrollo... Un saludo y gracias de nuevo.

yusnerqui 26-12-2007 15:28:46

En mi delphi 7 los datafields no tienen esta propiedad tan útil(Modified),sino que aparece como un atributo del TDataset para saber si se ha modificado el rejistro actual.
Alguien sabe a partir de que versión está incorporada?.

Gracias

Garry 09-01-2008 10:40:13

Lo he buscado, pero ni idea, yusnerqui. ¿Es relevante la versión? :D

Lepe 09-01-2008 11:18:51

Al decir DataField me pierdo un poco.

En Delphi 7 (y supongo que anteriores) está definida en la clase TField, por tanto, TStringField, TintegerField, TFloatField, etc ya tienen dicha propiedad.

El TDataset, también la incorpora, es obvio que al modificar el valor de un TField, automáticamente se propaga a su TDataset correspondiente.

Alguna vez, cuando traté de trabajar con dicha propiedad, creo que en el afterScroll debes resetear esa propiedad porque se pone a True. Primero intenta usarla, si ves que tiene algún comportamiento extraño, entonces revisa este comentario.

Saludos

courtois 11-01-2008 02:30:04

y no te sirve la propiedad OldValue?, hace exactamente lo que quieres hacer con OldText, y tambien tienes NewValue para que hagas las compraciones de si realmente cambio algo o no antes de hacer un post.

Garry 14-01-2008 09:39:34

Molto gracce
 
Gracias, chicos, me habéis ayudado mucho. Creo que me habéis orientado perfectamente por dónde empezar...

Me parece que lo de Cache Updates va a ser lo que necesito, a ver si me manejo y encuentro pronto su ubicación :p

Un saludo desde Coruña (España) :)


La franja horaria es GMT +2. Ahora son las 12:08:46.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi