2008-12-07 9 views
6

Der Titel sagt so ziemlich alles. Ich verwende ein TClientDataset, um ein Array von Objekten zu speichern, und eines der Objekte hat ein Element, das als -Set eines Aufzählungstyps definiert ist. Wie ich es verstehe, sind Delphi-Sets Bitfelder, deren Größe je nach Datenmenge zwischen 1 und 32 Byte variieren kann, und Delphi definiert kein TSetField. In welches Feld soll ich diesen Wert laden?Was ist der beste Weg, um ein Delphi-Set in einem Dataset zu speichern?

+0

Siehe auch [So speichern/laden Sie eine Typengruppe?] (Http://stackoverflow.com/q/9553510/757830). – NGLN

Antwort

14

Sie einen TBytesField oder eine TBlobField verwenden könnte

ClientDataSet1MySet: TBytesField, Größe = 32

var 
    MySet: set of Byte; 
    Bytes: array of Byte; 
begin 
    MySet := [1, 2, 4, 8, 16]; 

    // Write 
    Assert(ClientDataSet1MySet.DataSize >= SizeOf(MySet), 'Data field is too small'); 

    SetLength(Bytes, ClientDataSet1MySet.DataSize); 
    Move(MySet, Bytes[0], SizeOf(MySet)); 
    ClientDataSet1.Edit; 
    ClientDataSet1MySet.SetData(@Bytes[0]); 
    ClientDataSet1.Post; 

    // Read 
    SetLength(Bytes, ClientDataSet1MySet.DataSize); 
    if ClientDataSet1MySet.GetData(@Bytes[0]) then 
    Move(Bytes[0], MySet, SizeOf(MySet)) 
    else 
    MySet := []; // NULL 
end; 
+0

Es ist besser als meins. Und klarer ... Cool –

+0

1) Um Ihre Probe noch übersichtlicher zu machen, schlage ich vor, die "ClientDataSet1MySet.SetData (@Bytes [0])" in "ClientDataSet1MySet.AsBytes: = Bytes" 2) Im // Read-Block zu ändern (in der Move-Zeile), ich denke, dass Sie die "SizeOf (MySet)" in "ClientDataSet1MySet.DataSize" müssen, um konsistent zu sein. – rvheddeg

2

Sie können sie auf Byte konvertieren, wie folgt aus:

var 
    States : TUpdateStatusSet; // Can be any set, I took this one from DB.pas unit 
    SetAsAInteger: Integer; 
    dbs: Pointer; // Here's the trick 
begin 
    States := [usModified, usInserted]; // Putting some content in that set 
    dbs := @States; 
    SetAsAInteger := PByte(dbs)^; 
    //Once you got it, SetAsAInteger is just another ordinary integer variable. 
    //Use it the way you like. 
end; 

Zur Gewinnung von überall:

var 
    MSG: string; 
    Inserted, Modified: string; 
    States: TUpdateStatusSet; 
    MySet: Byte; 

begin 
    while not ClientDataSet.Eof do 
    begin 
    //That's the part that interest us 
    //Convert that integer you stored in the database or whatever 
    //place to a Byte and, in the sequence, to your set type. 
    iSet := Byte(ClientDatasetMyIntegerField);// Sets are one byte, so they 
               // fit on a byte variable 
    States := TUpdateStatusSet(iSet); 
    //Conversion finished, below is just interface stuff 


    if usInserted in States then 
     Inserted := 'Yes'; 
    if usModified in States then 
     Modified := 'Yes'; 
    MSG := Format('Register Num: %d. Inserted: %s. Modified:%s', 
        [ClientDataSet.RecNo, Inserted, Alterted]); 
    ShowMessage(MSG); 
    ClientDataset.Next; 
    end; 

end; 
+0

Das funktioniert gut, bis Sie mehr als 32 Bits benötigen. Sätze gehen bis zu 256 Bits, und ich bin in einer Situation, in der ich einen guten Teil dieses Raumes brauchen könnte. –

+0

Ich werde versuchen, dieses Szenario anzupassen. –

0

Nach dem Beispiel von Andreas, aber etwas einfacher und klarer IMHO gemacht.

auf XE2 Getestet

Sie einen TBytesField oder eine TBlobField verwenden könnte

ClientDataSet1MySet: TBytesField, Größe = 32

1) Schreiben

var 
    MySet: set of Byte; 
    Bytes: TBytes; 
begin 
    MySet := [0]; 

    // Write 
    Assert(ClientDataSet1Test.DataSize >= SizeOf(MySet), 'Data field is too small'); 

    SetLength(Bytes, ClientDataSet1Test.DataSize); 
    Move(MySet, Bytes[0], SizeOf(MySet)); 
    ClientDataSet1.Edit; 
    ClientDataSet1Test.AsBytes := Bytes; 
    ClientDataSet1.Post; 
end; 

2) Lesen

var 
    MyResultSet: set of Byte; 
begin 
    Move(ClientDataSet1Test.AsBytes[0], MyResultSet, ClientDataSet1Test.DataSize); 
end; 
Verwandte Themen