2016-10-05 2 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를 데이터 필드와 유사한 행동해야하고 데이터를 다시로드 (가까이와 데이터 집합을 다시) 할 필요가 없습니다 AFAIK이 도움말을 하는가하면 ? 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의 datapacket을 정의하는 METADATA에 추가 FIELD 노드를 추가 할 사소한 변화를 만들기 위해 MSXML 또는 좋아하는 XML 프로세서를 사용할 수 있습니다. 그런 다음 XML에서 CDS를 다시로드합니다. 추가 된 필드 값은 물론 NULL이며이 기법을 사용하려면 저장된 XML에서 CDS를 다시로드 할 때 영구 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에 추가하는 것은 물론, 문자열 - twiddling을 일정량 수행 할 준비가 되었다면 TStringList에로드하여 추가 할 수도 있습니다.

Fwiw, 나는 XML 파일의 각 ROW 노드에 대한 추가 정보를 포함하도록 CDS의 XML을 수정하려고 할 때이 규칙을 발견했습니다. LoadFromFile & LoadFromStream 개의 프로세스가 내가 추가 한 정보를 전혀 알지 못한다는 것이 밝혀졌습니다.

+0

이것은 유효한 대답이며 실제로 상상했던 것보다 구현하기가 쉽습니다. 그러나 나는 위에서 설명한 "지저분한"솔루션에 비해이 접근법에 이점을 실제로 볼 수 없습니다. –

+0

그 자신에게 각각, 나는 짐작한다. 필자가이 방법을 선호하는 이유는 "도구 상자"루틴으로 다시 작성한다는 것입니다. 그러면 입력을 통해 필요한 것은 추가 할 필드 (및 선택적으로 초기 필드 값)를 정의하는 약간의 XML입니다. – MartynA

-1

흠, 계산 된 필드가 잘못 되었나요? 왜 그걸 사용하고 싶지 않은지 설명해 주시겠습니까?

추가 힌트 : InternalCalc (FieldKind = fkInternalCalc)를 사용해 보셨습니까? 당신이 계산 된 필드

+0

이것은 [link] (http://i.imgur.com/4mLIlil.png)의 목표입니다. 즉, 이전에 저장 한 데이터 세트에 새 데이터 (새 필드)를 추가하십시오. InternalCalc는 아무런 차이가 없으며 SaveToFile을 호출 할 때 디스크에 저장되지 않습니다. 계산 된 필드를 사용하고 싶지 않은 이유는 무엇입니까? 이전 버전과의 호환성에 대한 것입니다. 오래된 구조의 야생에 저장된 많은 "파일"이 있습니다. 사용자가 열어서 다시 저장하면 이전 파일에 새 속성을 추가해야합니다. TClientDataSet은 그 작업을 쉽게하지 못합니다! –

+0

사이드 노트 : 열려있는 TClientDataSet에 새로운 InternalCalc 필드를 추가하면 '열려있는 데이터 세트에서이 작업을 수행 할 수 없습니다.'라는 메시지가있는 EDatabaseError가 발생합니다 .' –

관련 문제