2008-12-07 23 views
6

El título casi lo dice todo. Estoy usando un TClientDataset para almacenar una matriz de objetos, y uno de los objetos tiene un miembro definido como conjunto de un tipo enumerado. Tal como lo entiendo, los conjuntos de Delphi son bitfields cuyo tamaño puede variar de 1 a 32 bytes, según la cantidad de datos que contengan, y Delphi no define un TSetField. ¿Qué tipo de campo debo usar para cargar este valor?¿Cuál es la mejor manera de almacenar un conjunto de Delphi en un conjunto de datos?

+0

Véase también [¿Cómo guardar/cargar un conjunto de tipos?] (Http://stackoverflow.com/q/9553510/757830). – NGLN

Respuesta

14

Se puede usar un TBytesField o una TBlobField

ClientDataSet1MySet: TBytesField, Tamaño = 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 mejor que el mío. Y más claro ... Cool –

+0

1) Para que su muestra sea aún más clara, propongo cambiar "ClientDataSet1MySet.SetData (@Bytes [0])" en "ClientDataSet1MySet.AsBytes: = Bytes" 2) En el bloque // Read (en la línea Mover), creo que debe cambiar "SizeOf (MySet)" a "ClientDataSet1MySet.DataSize" para que sea coherente. – rvheddeg

2

Puede convertirlos en bytes, de esta manera:

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; 

Para recuperarse de en cualquier lugar:

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

Eso funciona bien hasta que necesite más de 32 bits. Los conjuntos alcanzan hasta 256 bits, y estoy en una situación en la que podría necesitar una buena fracción de ese espacio. –

+0

Intentaré adaptar esto a ese escenario. –

0

Basado en el ejemplo de Andreas, pero en mi humilde opinión es algo más simple y claro.

probado en XE2

Se puede usar un TBytesField o una TBlobField

ClientDataSet1MySet: TBytesField, Tamaño = 32

1) Escritura

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) Leyendo

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