2016-10-05 16 views
0

新しいデータフィールドを古いデータセットファイルに追加する方法を検討していません。たとえば、古いデータセットにはIDフィールドしかない場合があります。後で、ISACTIVEフィールドが必要であると判断します。 IDのみのデータを再度開き、ISACTIVE値を追加して再保存します。たとえば、Delphi ClientDataSet - 既存のデータセットに新しいデータフィールドを追加する方法?

CDS := TClientDataset.Create(nil); 
with TIntegerField.Create(CDS) do 
begin 
    FieldName := 'ID'; 
    FieldKind := fkData; 
    DataSet := CDS; 
end; 
CDS.CreateDataSet; 

CDS.Close; 
with TBooleanField.Create(CDS) do 
begin 
    FieldName := 'ISACTIVE'; 
    FieldKind := fkData; 
    DataSet := CDS; 
end; 
CDS.Open; // <--Raises EDatabaseError with message 'Field 'ISACTIVE' not found'. 

私は同様の質問をしましたが、私が見つけたのは、新しい計算フィールドをデータセットに追加することだけでした。上記のこのメソッドは、計算フィールドを追加するためには問題ありません。

私が考えることができる唯一の(厄介な)解決策は、ID専用データを一時データセットにロードし、IDとISACTIVEフィールドが定義された新しいデータセットを作成し、ID専用データセットレコードを新しいデータセットにコピーします。

+0

を追加するとき私の知る限り、それは、PS(それの値はデータセットのレコード内に格納されている)

をデータフィールドに似て振る舞うべきで、(クローズおよびデータセットを再度開く)データをリロードする必要はありませんこのヘルプあなたをい? http://stackoverflow.com/questions/21293186/delphi-change-fields-definitions-of-a-tclientdataset-that-has-data – Graymatter

+0

ちょっと、ちょっと。それは私が思っている非常に奇妙に提起された質問ですか?とにかく、この回答http://stackoverflow.com/a/21295035/6620329私の質問の最後に "かすかな"ソリューションと呼ばれるものを説明します。多分それは私には利用可能な唯一のオプションです(バーMartynAの提案は、ディスク上のテキストファイルを編集することです)。 –

答えて

1

これを行う簡単な方法があります。

あなたが整数IDフィールドと文字列80名フィールドでCDSを持っている、とあなたは結果のXMLファイルは次のようになります

AFileName := 'C:\Temp\CDSData.Xml'; 
CDS1.SaveToFile(AFileName, dfXML); 

のように、XMLにデータセットを保存した場合(D7用)

<?xml version="1.0" standalone="yes"?> 
<DATAPACKET Version="2.0"> 
    <METADATA> 
    <FIELDS> 
     <FIELD attrname="ID" fieldtype="i4"/> 
     <FIELD attrname="Name" fieldtype="string" WIDTH="80"/> 
    </FIELDS><PARAMS CHANGE_LOG="1 0 4"/> 
    </METADATA> 
    <ROWDATA> 
    <ROW RowState="4" ID="1" Name="one"/> 
    </ROWDATA> 
</DATAPACKET> 

あなたは余分なフィールドを追加するには、CCDSのデータパケットを定義METADATAに追加FIELDノードを追加するために些細な変更を行うためにMSXMLたり、お気に入りのXMLプロセッサを使用することができます。その後、XMLからCDSをリロードします。追加されたフィールドの値はもちろんNULLになります。この手法を使用するには、保存されたXMLからリロードする際に、永続TFieldをCDSに定義してはいけません。

コード例:明らかに

procedure TForm1.CopyWithAddedFields; 
var 
    SS : TStringStream; 
    XMLDoc : IXmlDomDocument; 
    FieldsNode : IXmlDomNode; 
    FieldElement : IXmlDomElement; 
begin 
    SS := TStringStream.Create(''); 
    try 
    // Save the CDS's current contents in XML format, close it and clear any presistent fields 
    CDS1.SaveToStream(SS, dfXML); 
    CDS1.Close; 
    CDS1.Fields.Clear; 

    // Next create an XML Document object and load the saved dataset into it 
    XMLDoc := CoDomDocument.Create; 
    XMLDoc.LoadXML(SS.DataString); 

    // Find the FIELDS node and add a new FIELD node to it  
    FieldsNode := XMLDoc.selectSingleNode('/DATAPACKET/METADATA/FIELDS'); 
    FieldElement := XMLDoc.createElement('FIELD'); 
    FieldElement.SetAttribute('attrname', 'Active'); 
    FieldElement.SetAttribute('fieldtype', 'boolean'); 
    FieldsNode.appendChild(FieldElement); 

    // Save the XML to the stream 
    SS.Size := 0; 
    SS.WriteString(XmlDoc.xml); 
    SS.Position := 0; 

    // Reload the ClientDataset 
    CDS1.LoadFromStream(SS); 
    finally 
    XMLDoc.Free; 
    SS.Free; 
    end; 
end; 

あなたがしたい場合は、代わりに別のCDSに変更されたXMLを読み込むことができます。

もちろん、特別な文字列 - ツイディリングを自分で行う準備ができていれば、余分なFIELDノードをXMLに追加することもできます。

私は、XMLファイル内の各ROWノードの追加情報を含むようにCDSのXMLを変更しようとしたときに、このルーズを見つけました。 LoadFromFile & LoadFromStreamのプロセスは、私が追加した情報を完全に忘れていたことが判明しました。

+0

これは有効な答えですが、私が想像していたよりも実装が簡単です。しかし、私は上記の "厄介な"解決策よりもこのアプローチに利点があるとは思えません。 –

+0

彼自身がそれぞれ、私はそう思います。私がこのアプローチを自分で好む理由は、ツールボックスのルーチンとして書き直すということです。追加するフィールドを定義するXML(およびオプションで初期フィールド値)を入力するだけで十分です。 – MartynA

-1

ええと、計算されたフィールドに間違いはありますか?なぜあなたはそれらを使いたくないのか説明してください。

追加のヒント1つ:InternalCalc(FieldKind = fkInternalCalc)を試したことがありますか?あなたは計算フィールド

+0

これは目的です:[link](http://i.imgur.com/4mLIlil.png)。 つまり、以前に保存したデータセットに新しいデータ(新しいフィールド)を追加します。 InternalCalcかどうかは違いはなく、SaveToFileを呼び出すとどちらもディスクに保存されません。なぜ私は計算フィールドを使用したくないのですか?下位互換性についてです。古い構造を持つ野生の多くの保存された "ファイル"があります。ユーザーが開いて再保存したときに古いファイルに新しいプロパティを追加する必要があります。 TClientDataSetはそのタスクを簡単にしません! –

+0

サイドノート:開いているTClientDataSetに新しいInternalCalcフィールドを追加すると、 '開いているデータセットに対してこの操作を実行できません。'というメッセージのあるEDatabaseErrorが発生します。 –

関連する問題