2008-12-07 47 views
6

Tiêu đề khá nhiều nói lên tất cả. Tôi đang sử dụng một TClientDataset để lưu trữ một mảng các đối tượng, và một trong các đối tượng có một thành viên được định nghĩa là một bộ của một kiểu liệt kê. Như tôi đã hiểu, các bộ Delphi là các bitfield có kích thước có thể thay đổi từ 1 đến 32 byte tùy thuộc vào lượng dữ liệu chúng chứa, và Delphi không định nghĩa một TSetField. Tôi nên sử dụng loại trường nào để tải giá trị này vào?Cách tốt nhất để lưu trữ tập Delphi trong tập dữ liệu là gì?

+0

Xem thêm [Cách lưu/tải Tập hợp loại?] (Http://stackoverflow.com/q/9553510/757830). – NGLN

Trả lời

14

Bạn có thể sử dụng một TBytesField hoặc một TBlobField

ClientDataSet1MySet: TBytesField, Kích thước = 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

Nó tốt hơn tôi. Và rõ ràng hơn ... Cool –

+0

1) Để làm cho mẫu của bạn rõ ràng hơn, tôi đề xuất thay đổi "ClientDataSet1MySet.SetData (@Bytes [0])" thành "ClientDataSet1MySet.AsBytes: = Bytes" 2) Trong // Read block (trên dòng Move), tôi nghĩ rằng bạn phải thay đổi "SizeOf (MySet)" thành "ClientDataSet1MySet.DataSize" để nhất quán. – rvheddeg

2

Bạn có thể chuyển đổi chúng sang Byte, như thế này:

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; 

Để khắc phục ở bất kỳ đâu:

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

Chỉ hoạt động tốt cho đến khi bạn cần hơn 32 bit. Các bộ đi lên tới 256 bit và tôi đang ở trong tình huống mà tôi có thể cần một phần nhỏ của không gian đó. –

+0

Tôi sẽ cố gắng điều chỉnh điều này theo kịch bản đó. –

0

Dựa trên ví dụ về Andreas, nhưng làm IMHO đơn giản và rõ ràng hơn.

Thử nghiệm trên XE2

Bạn có thể sử dụng một TBytesField hoặc một TBlobField

ClientDataSet1MySet: TBytesField, Kích thước = 32

1) Viết

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) Đọc

var 
    MyResultSet: set of Byte; 
begin 
    Move(ClientDataSet1Test.AsBytes[0], MyResultSet, ClientDataSet1Test.DataSize); 
end; 
Các vấn đề liên quan