2008-12-07 1 views
6

Название довольно много говорит обо всем. Я использую TClientDataset для хранения массива объектов, а один из объектов имеет элемент, определенный как набор перечисляемого типа. Насколько я понимаю, наборы Delphi являются битовыми полями, размер которых может варьироваться от 1 до 32 байтов в зависимости от того, сколько данных они содержат, а Delphi не определяет TSetField. Какую область я должен использовать для загрузки этого значения?Каков наилучший способ хранения Delphi в наборе данных?

+0

См. Также [Как сохранить/загрузить набор типов?] (Http://stackoverflow.com/q/9553510/757830). – NGLN 2015-12-25 20:27:34

ответ

14

Вы можете использовать TBytesField или TBLOBField

ClientDataSet1MySet: TBytesField, размер = 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

Это лучше, чем у меня. И яснее ... Cool – 2009-07-22 19:17:50

+0

1) Чтобы сделать ваш образец еще более ясным, я предлагаю изменить «ClientDataSet1MySet.SetData (@Bytes [0])» в «ClientDataSet1MySet.AsBytes: = Bytes» 2) В блоке // Read (в строке «Перемещение»), я думаю, что вы должны изменить «SizeOf (MySet)» на «ClientDataSet1MySet.DataSize», чтобы быть последовательным. – rvheddeg 2013-12-04 16:55:33

2

Вы можете конвертировать их в байт, как это:

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; 

Для восстановления в любом месте:

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

Основано на примере Андреаса, но сделано несколько проще и понятнее ИМХО.

Проверено на XE2

Вы можете использовать TBytesField или TBLOBField

ClientDataSet1MySet: TBytesField, размер = 32

1) Запись

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) Чтение

var 
    MyResultSet: set of Byte; 
begin 
    Move(ClientDataSet1Test.AsBytes[0], MyResultSet, ClientDataSet1Test.DataSize); 
end; 
Смежные вопросы