Ver Mensaje Individual
  #7  
Antiguo 11-02-2011
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Reputación: 30
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 Josep.

Fue un total desafío leer tu último mensaje carente de acentos, pero lo comprendí a grandes rasgos. Nada más por eso me debes una cerveza León.

Sin proponer una alternativa a la estructura de la información, existen dos sencillas formas de solucionar el problema a nivel del conjunto de datos cliente:

1.

Mi recomendación es que no agregues esos registros al conjunto de datos 1 mediante los métodos Insert, Append, InsertRecord o AppendRecord. Todos ellos emplean mecanismos que están pensados para "nuevas capturas", es decir, registros que al ser agregados al conjunto de datos cliente se anotan en la lista de cambios (change log) de éste. Y como has de saber ya, al llamar a ApplyUpdates esa lista de cambios es enviada al servidor.

Mejor utiliza el método AppendData así:

Código Delphi [-]
CDS1.AppendData (CDS2.Data, True);

Eso hará que todos los registros contenidos en el conjunto de datos 2 (CDS2) se copien a la lista de registros del conjunto de datos 1 (CDS1), pero sin que se marquen como "nuevos", es decir, sin aparecer en la lista de cambios. Tales registros se mezclarán con los ya existentes sin distinción especial alguna por parte de CDS1.

2.

Si te vieras forzado a utilizar los tradicionales métodos Append, Insert, etc., aún podrías evitar que los registros agregados se anotaran en la lista de cambios. Para ello se requiere desactivar la propiedad LogChanges temporalmente:

Código Delphi [-]
CDS1.LogChanges := False;

Try
  { Añadimos registros a CDS1 con Append...Post, pero no se enlistarán en 
     el "change log" }
Finally
  CDS1.LogChanges := True;
End;

Como podrás ver, resulta más fácil usar AppendData que poner temporalmente en False la propiedad LogChanges, pero hay algo que debes saber sobre el provechoso método AppendData:

Si CDS1 tiene campos de tipo InternalCalc, tales campos no se copiaran aunque estén presentes también en CDS2. La razón de ello no la tengo muy clara, pero se encuentra en las entrañas de MIDAS, cuyos fuentes en C++ (hechos públicos a partir de Delphi 2010) he tenido la fortuna de poder revisar, aunque sin mucha profundidad aún. En ellos he encontrado extractos como:

Código:
         // This test must come after
         if (iFieldID > pDs->iFieldsDataPacket)
         {
            // Calculated fields ? Do not read from pickle
            continue;
         }
Código:
      if (bAppend)
      { // Updates calculated fields, indexes, aggregates, iRecNoNext etc.
         // NOTE: currently does not update calculated fields
         rslt = pDs->InsertRecord(NULL, NULL);
         if (rslt)
            break;
      }
Código:
      for (i = 0; i < pDs->iFields; i++)
      { // Disregard blob/calculated fields
         BOOL bBlank = FALSE;

         pDs->GetField(pRecUpd, i+1, NULL, &bBlank);
Quien vea las rutinas completas notará que esos fuentes poseen un marcado estilo presuroso, propio de un programador C duro de la vieja guardia; contrastan con la elegancia de código que podemos ver en muchos archivos .pas de la VCL. Sospecho que Borland le encargó la elaboración de la biblioteca MIDAS.dll a un programador externo a su plantilla, quizá famoso por escribir algoritmos de rápida ejecución (eso se reconoce), pero tal vez él ya se retiró o vaya usted a saber, porque, según he podido colegir, esos fuentes siguen siendo prácticamente los mismos desde versiones como la 7.

Es como si el fabricante de Delphi tuviera miedo de tocarlos, acaso por no tener idea clara de cómo trabajan. Y entonces uno se explica por qué el componente TClientDataSet, lleno de tantas cualidades (se reconoce también), presenta, bajo circunstancias muy precisas, algunos "extraños" en su funcionamiento (como éste).

Cierro el paréntesis psicológico para volver al punto: El problema de AppendData es que por no incluirse los campos InternalCalc en la copia, ocurre cierto defecto (bug) con una bandera interna de dichos campos (el byte blank flag). Si CDS1 tiene campos InternalCalc y le haces múltiples llamadas a su método AppendData, los primeros registros aparecerán con esos campos en blanco (algo que puede no representar ningún problema), pero eventualmente, en registros agregados con posteriores llamadas a AppendData, tales campos vendrán con su bandera "blank" en 0 en lugar de 1, lo que se traduce en que serán tomados como campos que sí tienen valor, pero cuyo contenido será incierto. De hecho este defecto es causa de la excepción "'0.0' is not a valid timestamp", cuando se tiene un campo InternalCalc de tipo fecha en el conjunto de datos y se hacen múltiples llamadas a AppendData.

He realizado algunas pruebas, y al parecer eso puede ser corregido mediante el uso del método DSBase.PutBlank. Pero no nos adelantemos, Josep; quizá no tienes campos InternalCalc en CDS1, o quizá no realizas tantas llamadas sucesivas a su método AppendData como para producir el efecto mencionado. Así que ese método puede resultarte efectivo.

Coméntanos al respecto.

Un abrazo en C++ ({).

Al González.

Última edición por Al González fecha: 11-02-2011 a las 08:17:57.
Responder Con Cita