Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Trying to modify a Read-Only Field (ClientDataSet)

Saludos amigos, a ver si me pueden ayudar, estoy teniendo un pequeño problema con un clientdataset, al intentar editar los datos de un campo mediante un bucle While, solo me modifica el registro la primera vez, luego al intentar modificar la segunda linea siempre me dispara el error 'Tryin to Modify a Read-Only Field'.

He verificado que el ClientDataSet no este Read-Only, ni el campo a modificar tampoco lo esta, y ya no se me ocurre nada que pueda ser.

Si alguien sabe algo al respecto que me pueda hechar una mano please.
Responder Con Cita
  #2  
Antiguo 25-08-2010
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola Dclase.

¿ Un poco de código por favor ?

Saludos.
Responder Con Cita
  #3  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Código Delphi [-]
With ClientDataSet1 Do
Begin

ClientDataSet1.Close;
ClientDataSet1.Commantext := ' Select * from Tabla1';
ClientDataSet1.Open
  If Not Eof Then
  Begin
     First;
     While Not Eof Do
     Begin
         ClientDataSet2.Edit;  //Este Cds no esta conectado a ningun provider 
                                      //Solo lo utilizo para actializar datos en memoria
         ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat;
     Next; 
     End;
  End;

End;

Cuando entra al bucle por primera vez edita el primer registo, pero el siguiente ya me dispara el mensaje de que no puede modificar..
Responder Con Cita
  #4  
Antiguo 25-08-2010
Avatar de Caro
*Caro* Caro is offline
Moderadora
 
Registrado: jul 2004
Ubicación: Cochabamba, Bolivia
Posts: 2.544
Poder: 22
Caro Va por buen camino
Hola DClase, así como esta tu codigo, recorres el ClientDataSet1 y actualizas el registro actual del ClientDataSet2 pero siempre el mismo (para hacer eso no necesitas un ciclo, actualizas directamente el registro actual). Puedes probar de poner un Post:

Código Delphi [-]
 ..............................................
 ClientDataSet2.Edit;
 ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat;
 ClientDataSet2.Post;
 ..............................................

Saluditos
__________________
Disfruten cada minuto de su vida a lado de sus seres queridos como si fuese el ultimo, uno nunca sabe lo que puede pasar.
Responder Con Cita
  #5  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Perdon, me falto algo de codigo, previamente lleno el ClienteDataSet2 con campos de una tabla, (TablaA), luego lo recorro y actualizo un registro X de otra tabla (TablaB).


Código Delphi [-]
With ClientDataSet3 Do
Begin
   Close;
   ClientDataSet1.Commantext := ' Select * from TablaA';
   Open
     If Not Eof Then
     Begin
        First;
        While Not Eof Do
        Begin   
          ClientDataSet2.Append;
          ClientDataSet2.FieldByName('Codigo').AsString := FieldByName('Codigo').AsString;
           ClientDataSet2.FieldByName('CAMPO1').AsFloat := 0;
        Next;
        End;
     End;
End;


With ClientDataSet1 Do
Begin

ClientDataSet1.Close;
ClientDataSet1.Commantext := ' Select * from TablaB';
ClientDataSet1.Open
  If Not Eof Then
  Begin
     First;
     While Not Eof Do
     Begin
         IF ClientDataSet2.Locate('Codigo', FieldByName('Codigo').AsString, []) Then
         Begin
         ClientDataSet2.Edit;  //Este Cds no esta conectado a ningun provider 
                                      //Solo lo utilizo para actializar datos en memoria
         ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat;
         End;
     Next; 
     End;
  End;

End;

Intento editar el campo si lo encuentra. No creo que sea por usar locate, porque tambien lo intente poniendo un While al ClientDataSet2 para recorrerlo y comparar registro por registro, pero igual me da el mismo error.
Responder Con Cita
  #6  
Antiguo 25-08-2010
Avatar de AzidRain
[AzidRain] AzidRain is offline
Miembro Premium
 
Registrado: sep 2005
Ubicación: Córdoba, Veracruz, México
Posts: 2.914
Poder: 21
AzidRain Va camino a la fama
El ciclo esta bien, pero nunca haces post, el Post debe quedar dentro del ciclo previo al Next.
__________________
AKA "El animalito" ||Cordobés a mucha honra||
Responder Con Cita
  #7  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
uhmm... no es por el 'Post', con el Post y sin el Post me sigue dando el error igual..
Responder Con Cita
  #8  
Antiguo 25-08-2010
Avatar de AzidRain
[AzidRain] AzidRain is offline
Miembro Premium
 
Registrado: sep 2005
Ubicación: Córdoba, Veracruz, México
Posts: 2.914
Poder: 21
AzidRain Va camino a la fama
En el código que pusiste no hay ningun post.
__________________
AKA "El animalito" ||Cordobés a mucha honra||
Responder Con Cita
  #9  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Igual con post y sin post me da el mismo error..


Código Delphi [-]
With ClientDataSet3 Do
Begin
   Close;
   ClientDataSet1.Commantext := ' Select * from TablaA';
   Open
     If Not Eof Then
     Begin
        First;
        While Not Eof Do
        Begin   
          ClientDataSet2.Append;
          ClientDataSet2.FieldByName('Codigo').AsString := FieldByName('Codigo').AsString;
           ClientDataSet2.FieldByName('CAMPO1').AsFloat := 0;
           ClientDataSet2.Post;
        Next;
        End;
     End;
End;


With ClientDataSet1 Do
Begin

ClientDataSet1.Close;
ClientDataSet1.Commantext := ' Select * from TablaB';
ClientDataSet1.Open
  If Not Eof Then
  Begin
     First;
     While Not Eof Do
     Begin
         IF ClientDataSet2.Locate('Codigo', FieldByName('Codigo').AsString, []) Then
         Begin
         ClientDataSet2.Edit;  //Este Cds no esta conectado a ningun provider 
                                      //Solo lo utilizo para actializar datos en memoria
         ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat;
         ClientDataSet2.Post;
         End;
     Next; 
     End;
  End;

End;

(Aproposito, el codigo aqui no importa, solo puse este de prueba para k se entienda mejor lo que queria explicar, pero si es la misma sintaxis y logica de lo que busco hacer.)
Responder Con Cita
  #10  
Antiguo 25-08-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por Dclase Ver Mensaje
Cuando entra al bucle por primera vez edita el primer registo, pero el siguiente ya me dispara el mensaje de que no puede modificar..
Así sucede porque es hasta la segunda pasada del ciclo cuando, por alguna sentencia de tu código (que quizá dispara un CheckBrowseMode indirecto), se desencadena la llamada al método Post que intenta guardar la operación anterior.

El método Post, llama a InternalPost, el cual, en el caso de TClientDataSet, llama a su vez al método ModifyRecord de su interfaz DSCursor. Este método verifica que ninguno de los campos que estén marcados como de sólo lectura haya sufrido cambios. Si pasa esta validación, el registro es guardado en la memoria del conjunto de datos, de lo contrario arrojará la excepción "Trying to modify read-only field".

El origen del problema es que antes de la operación de guardado el campo en cuestión fue marcado como read only.

Dices que ya revisaste eso, pero ¿podrías mostrarnos cómo estás creando el objeto ClientDataSet2 y definiendo sus campos?

Saludos.

Al.
Responder Con Cita
  #11  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Bueno, no se si en la forma en que lo utilizo sea la correcta, el ClientDataSet2, es un componente TClientDataSet que lo agrego en modo de diseño, lo conecto a un Provider el cual a su vez esta conectado a un TADODataSet (a este ultimo le paso un String con los campos k rekiero de una tabla en especifico), al activar el ClientDataSet, me trae los campos resultantes de la consulta, limpio la propiedad ProviderName, y ya tengo el ClientDataSet2 con los campos k requiero. Bueno y si vienen campos onla propiedad read-only = True, los cambio a False

Antes de trabajar con el ClientDataSet2 siempre lo limpio primero:
Código Delphi [-]
With ClientDataSet2 Do
Begin
   While IsEmpty = False Do
   Begin
      Delete;
   End;
End;

Luego entonces le inserto datos con Append;
y despues es que intento editarlo.

Siempre lo habia utilizado asi pero solo para modificar un registro a la vez y lo enviaba directamente a la tabla con ApplayUpdate(0), pero en este caso solo me interesa modificar en el CDS en memoria para fines de reporte.

Última edición por Dclase fecha: 25-08-2010 a las 23:41:59.
Responder Con Cita
  #12  
Antiguo 25-08-2010
Avatar de afunez2007
afunez2007 afunez2007 is offline
Miembro
 
Registrado: oct 2007
Ubicación: La Ceiba, Honduras
Posts: 170
Poder: 17
afunez2007 Va por buen camino
Lightbulb

Cita:
Empezado por Dclase Ver Mensaje
Igual con post y sin post me da el mismo error..


Código Delphi [-]With ClientDataSet3 Do Begin Close; ClientDataSet1.Commantext := ' Select * from TablaA'; Open If Not Eof Then Begin First; While Not Eof Do Begin ClientDataSet2.Append; ClientDataSet2.FieldByName('Codigo').AsString := FieldByName('Codigo').AsString; ClientDataSet2.FieldByName('CAMPO1').AsFloat := 0; ClientDataSet2.Post; Next; End; End; End; With ClientDataSet1 Do Begin ClientDataSet1.Close; ClientDataSet1.Commantext := ' Select * from TablaB'; ClientDataSet1.Open If Not Eof Then Begin First; While Not Eof Do Begin IF ClientDataSet2.Locate('Codigo', FieldByName('Codigo').AsString, []) Then Begin ClientDataSet2.Edit; //Este Cds no esta conectado a ningun provider //Solo lo utilizo para actializar datos en memoria ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat; ClientDataSet2.Post; End; Next; End; End; End;


(Aproposito, el codigo aqui no importa, solo puse este de prueba para k se entienda mejor lo que queria explicar, pero si es la misma sintaxis y logica de lo que busco hacer.)
veamos yo veo que hay un ciclo redundante el if para mi esta demas, prueba asi:
Código Delphi [-]
With ClientDataSet3 Do
Begin
   Close;
   ClientDataSet1.Commantext := ' Select * from TablaA';
   Open;
        First;
        While Not Eof Do
        Begin   
          ClientDataSet2.Append;
          ClientDataSet2.FieldByName('Codigo').AsString := FieldByName('Codigo').AsString;
           ClientDataSet2.FieldByName('CAMPO1').AsFloat := 0;
           ClientDataSet2.Post;
        Next;
        End;
End;


With ClientDataSet1 Do
Begin

ClientDataSet1.Close;
ClientDataSet1.Commantext := ' Select * from TablaB';
ClientDataSet1.Open;
     First;
     While Not Eof Do
     Begin
         IF ClientDataSet2.Locate('Codigo', FieldByName('Codigo').AsString, []) Then
         Begin
         ClientDataSet2.Edit;  //Este Cds no esta conectado a ningun provider 
                                      //Solo lo utilizo para actializar datos en memoria
         ClientDataSet2.FieldByName('CAMPO1').AsFloat := FieldByName('CAMPO1').AsFloat;
         ClientDataSet2.Post;
         End;
     Next; 
     End;
End;

a mi en lo personal, solo utilizaria el dataset para recoger el id del registro a modificar, y haria un Insert con un query o un update en el segundo ciclo, el tema de modificar directamente los datos del data set te suele provocar estos incomodos errorcillos
__________________
Si robas, roba un beso, si mientes que sea por amor y si engañas que sea a la muerte!!
Responder Con Cita
  #13  
Antiguo 25-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Cita:
Empezado por afunez2007 Ver Mensaje


............................
a mi en lo personal, solo utilizaria el dataset para recoger el id del registro a modificar, y haria un Insert con un query o un update en el segundo ciclo, el tema de modificar directamente los datos del data set te suele provocar estos incomodos errorcillos
Un update es lo que intento hacer en el segundo siclo buscando el id si existe del campo que ya inserte arriba.
Responder Con Cita
  #14  
Antiguo 26-08-2010
Avatar de afunez2007
afunez2007 afunez2007 is offline
Miembro
 
Registrado: oct 2007
Ubicación: La Ceiba, Honduras
Posts: 170
Poder: 17
afunez2007 Va por buen camino
Lightbulb

Cita:
Empezado por Dclase Ver Mensaje
Un update es lo que intento hacer en el segundo siclo buscando el id si existe del campo que ya inserte arriba.
Cuando te hablo de hacer un UPDATE, es a traves de sql y no directamente con un edit del data set.

Saludos
__________________
Si robas, roba un beso, si mientes que sea por amor y si engañas que sea a la muerte!!
Responder Con Cita
  #15  
Antiguo 26-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Cita:
Empezado por afunez2007 Ver Mensaje
Cuando te hablo de hacer un UPDATE, es a traves de sql y no directamente con un edit del data set.

Saludos

Hacer un Update mediante SQL, si es para aplicarlo directamente a una tabla MSSQL por ejemplo, si se como hacerlo, pero aqui no lo hago a una tabla, sino solo a un set de datos en memoria, ya que no me interesa salvar a una tabla el resultado, sino solo para fines de reporte.

Si hay una forma de hacerlo mediante Transac-SQL directamente al ClientDataSet en memoria les agradeceria me enseñen como..
Responder Con Cita
  #16  
Antiguo 26-08-2010
Avatar de afunez2007
afunez2007 afunez2007 is offline
Miembro
 
Registrado: oct 2007
Ubicación: La Ceiba, Honduras
Posts: 170
Poder: 17
afunez2007 Va por buen camino
Lightbulb

Cita:
Empezado por Dclase Ver Mensaje
Hacer un Update mediante SQL, si es para aplicarlo directamente a una tabla MSSQL por ejemplo, si se como hacerlo, pero aqui no lo hago a una tabla, sino solo a un set de datos en memoria, ya que no me interesa salvar a una tabla el resultado, sino solo para fines de reporte.

Si hay una forma de hacerlo mediante Transac-SQL directamente al ClientDataSet en memoria les agradeceria me enseñen como..
Comprendo, yo tuve unas complicaciones parecidas hace mucho tiempo con reportes, y tuve al final que buscar otras estrategias, lo solucione, creando tablas temporales directamente desde el codigo, Tempor_XX donde XX corresponde al numero de terminal, que esta lanzado el reporte y asi si que puedes realizar todas las sqls que quieras.

No digo que es lo que debas hacer tu, sin embargo si no lo solucionas con tu procedimiento actual no pierdas de vista la solucion que te he propuesto

Saludos
__________________
Si robas, roba un beso, si mientes que sea por amor y si engañas que sea a la muerte!!
Responder Con Cita
  #17  
Antiguo 26-08-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Hola de nuevo Dclase.

Lo primero sería comentarte que hay una mejor manera de crear un TClientDataSet bajo una estructura de campos específica. Para ello puedes hacer uso de su propiedad FieldDefs y de su método CreateDataSet. La ayuda de Delphi viene con un buen ejemplo y seguramente en este foro encontrarás varios ejemplos más.

Allende de lo anterior, me llamó la atención esto que comentaste:

Cita:
Empezado por Dclase Ver Mensaje
...el ClientDataSet2, es un componente TClientDataSet que lo agrego en modo de diseño, lo conecto a un Provider el cual a su vez esta conectado a un TADODataSet (a este ultimo le paso un String con los campos k rekiero de una tabla en especifico), al activar el ClientDataSet, me trae los campos resultantes de la consulta, limpio la propiedad ProviderName, y ya tengo el ClientDataSet2 con los campos k requiero. Bueno y si vienen campos con la propiedad ReadOnly = True, los cambio a False...
Hay que decir que cuando se cambia la propiedad ReadOnly de un campo perteneciente a un TClientDataSet que cargó sus datos mediante un objeto proveedor, tal cambio no tiene efecto sobre el cursor del conjunto de datos. El cursor es un objeto interno que manejan todos los conjuntos de datos cliente y dicho objeto contiene, entre muchos datos, una lista de descriptores de campos.

Estos descriptores son elementos que definen a cada uno de los campos del cursor, como su tipo, tamaño y si son de lectura y escritura o sólo lectura. Cuando el conjunto de datos es abierto, el cursor inicializa sus descriptores de campos con base en la información obtenida de parte del proveedor.

Así pues, si el conjunto de datos que es servido por el proveedor (el TADODataSet en tu caso) viene con un campo cuya propiedad ReadOnly es True, el respectivo descriptor en el interior del cursor cliente quedará marcado con un atributo de sólo lectura (constante fldAttrReadOnly). Algo curioso de este atributo es que solamente tiene efecto en las modificaciones, pero no en las inserciones de registros (por ello has podido agregar filas, pero no cambiarlas).

Viendo tu caso, me dediqué un rato a investigar y hacer pruebas de cómo se podría quitar ese atributo del descriptor, considerando que este es un objeto interno de la propiedad interfaz DSCursor del conjunto de datos.

La clave está en llamar al método SetProp de esa interfaz con una constante que no aparece en Delphi (al menos no hasta la versión 7), pero que al parecer existe en MIDAS desde hace tiempo: curpropFLD_MAKERW; además de proporcionar el número de campo en cuestión.

Creé esta rutina que sirve para quitar el atributo de sólo lectura de un campo, tanto a nivel de la propiedad ReadOnly como a nivel de su respectivo descriptor en el interior del cursor:

Código Delphi [-]
Type
  TClientDataSetAccess = Class (TClientDataSet);
Procedure MakeReadWrite (Const Field :TField);
Begin
  Field.ReadOnly := False;

  With TClientDataSetAccess (Field.DataSet As TClientDataSet) Do
    Check (DSCursor.SetProp (CURProp (4) { curpropFld_MakeRW },
      Field.FieldNo));
End;

// Ejemplo de uso
procedure TForm1.Button1Click(Sender: TObject);
begin
  MakeReadWrite (CDS.FieldByName ('Numero'));
end;

Hice la prueba y funciona, el conjunto de datos cliente permite hacer y guardar modificaciones hechas sobre campos que venían marcados como de sólo lectura.

Lo anterior puede sernos útil en algún momento, pero no está demás recordarle a Dclase mi sugerencia de usar el método CreateDataSet, ya que además de emplear menos memoria de programa, no tendrá que hacer consulta alguna a la base de datos.

Saludos a FGarcia, por quien supe que existía la constante curpropFld_MakeRW.

Un abrazo.

Al González.
Responder Con Cita
  #18  
Antiguo 26-08-2010
Dclase Dclase is offline
Miembro
 
Registrado: ene 2007
Posts: 35
Poder: 0
Dclase Va por buen camino
Gracias [Al González] utilicé la propiedad FieldDefs para crear los campos y el CreateDataSet para crear mi set de datos como me dijiste y asi me ha funcionado bien. Pero Tambien veo interesante lo del descriptor en el interior del cursor , no sabia que existia esa parte del ClientDataSet ni esas propiedades y referencias internas.

Lo que si no me funcionó de tu codigo fue la variable (o atributo) "CURProp" en
Código Delphi [-]
........................
    Check (DSCursor.SetProp (CURProp (4) { curpropFld_MakeRW },
.......................

No se si porque no lo estoy poniendo donde va, o me falta agregar alguna libreria o algo por el estilo.

Gracias por tu aporte..
Responder Con Cita
  #19  
Antiguo 26-08-2010
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por Dclase Ver Mensaje
Gracias [Al González] utilicé la propiedad FieldDefs para crear los campos y el CreateDataSet para crear mi set de datos como me dijiste y asi me ha funcionado bien.
¡Estupendo!

Cita:
Empezado por Dclase Ver Mensaje
Pero Tambien veo interesante lo del descriptor en el interior del cursor , no sabia que existia esa parte del ClientDataSet ni esas propiedades y referencias internas.

Lo que si no me funcionó de tu codigo fue la variable (o atributo) "CURProp" en
Código Delphi [-]
........................
    Check (DSCursor.SetProp (CURProp (4) { curpropFld_MakeRW },
.......................

No se si porque no lo estoy poniendo donde va, o me falta agregar alguna libreria o algo por el estilo.

Gracias por tu aporte..
De nada Dclase. La unidad de biblioteca (que no librería ) que habría que referir en el código es DSIntf. Ésta contiene la declaración de varias interfaces como IDSCursor, y muchos tipos de datos y constantes relacionados con ella.

Código Delphi [-]
Uses
  DSIntf;

Saludos.

Al González.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Cannot Modify mantraxer21 Varios 8 26-08-2010 18:17:22
Error 'Cannot modify a read-only dataset' karaoke Varios 8 10-12-2007 06:38:31
Al intentar modificar un campo me dice "Cannot modify a read-only dataset" raulahol SQL 1 22-01-2007 05:16:53
error cannot modify a read-only dataset Renees Varios 2 30-09-2006 00:39:27
Query1 cannot modify a read-only dataset Nbull SQL 14 14-12-2004 10:29:35


La franja horaria es GMT +2. Ahora son las 12:51:01.


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