TClientDataSet duplizieren

Von einer Zeile eines TClientDataSet eine Kopie erstellen? “Nichts Einfacheres” habe ich mir gedacht – da war ich allerdings etwas voreilig. Wie bei anderen Dingen auch, so findet sich auch hierzu in den Dokumentationen von Borland/CodeGear/Embarcadero nur spärlich Information.

Warum einfach, wenn man’s mit dem CPP Builder auch machen kann?

Gewiss: Man könnte Spalte für Spalte die Werte zwischenspeichern und nach einem TClientDataSet::Append() einfach wieder einfügen. Nicht sehr elegant. Es sollte doch nur die aktive Row (bzw. deren Inhalte) eines ClientDataSet (CDS) in eine neue Zeile kopiert werden.

Nach einigem Hin und Her und der Berücksichtigung etlicher umständlicher Ratschläge aus diversen Foren habe ich dann doch noch einen einigermaßen gangbaren Weg gefunden:

// Angenommen TClientDataSet *CDS ist ein Member der Klasse

// Zuerst müssen wir von unserem CDS einen Clone erstellen
TClientDataSet *ClonedSet = new TClientDataSet( this );
ClonedSet->CloneCursor( this->CDS, false );

// Jetzt kann eine neue Zeile angelegt werden
this->CDS->Append();

// Feldweise die Daten kopieren, allerdings nicht:
// 1. das PK-Feld (wenn es sich um ein AutoIncrement-Feld handelt
// 2. die Felder die ReadOnly sind
for ( int i = 0; i < this->CDS->FieldCount; i++ )
{
    if
    (
        this->CDS->Fields->Fields[i]->AutoGenerateValue != arAutoInc &&
        this->CDS->Fields->Fields[i]->ReadOnly == false
    )
    {
        // Vorsicht, Falle: nicht einfach per Index die beiden 
        // DataSets durchiterieren, diese sind nämlich nicht 
        // zwingend gleich. Umweg über FieldByName verwenden!
        this->CDS->Fields->Fields[i]->Value =
            ClonedSet->FieldByName(
                this->CDS->Fields->Fields[i]->FieldName 
            )->Value;
    }
}

// Speichern und aktualiseren, damit auch die per JOIN 
// verbundenen Spalten befüllt werden 
this->CDS->ApplyUpdates(-1); 
this->CDS->Refresh(); 
delete ClonedSet;

Ich vermute schwer, dass hier noch einiges zu ergänzen wäre, aber ich will hier nur den Kern des Problems eruieren.