Pregunta

I am a Delphi developer and a C# Developer. C# has the DataTable class that supports random access to Rows. Is there a third-party TDataSet (Delphi) component that is like DataTable (C#)?

¿Fue útil?

Solución

There's TClientDataSet class in Delphi, which functionality is similar to DataSet in .NET.

Otros consejos

You can use TADODataSet for a disconnected in-memory dataset as suggested by Ian. It is very powerful as opposed to TClientDataSet IMO.

But all the low level ADO stuff is not needed. it is simple as:

var 
   ds: TADODataSet;

ds := TADODataSet.Create(nil);

//add our fields
ds.FieldDefs.Add('InvoiceNumber', ftInteger);
ds.FieldDefs.Add('CustomerName',  ftWideString, 200);
ds.FieldDefs.Add('CreatedDate',   ftDateTime);
ds.FieldDefs.Add('Comments',      ftWideMemo);
ds.FieldDefs.Add('Quantity',      ftFloat);
ds.FieldDefs.Add('InvoiceTotal',  ftCurrency);
ds.CreateDataSet;

//Add a row of values - the easy way
ds.Append;
ds.FieldByName('InvoiceNumber').AsInteger := 1783;
ds.FieldByName('CustomerName').AsString   := 'Hubert Farnsworth';
ds.FieldByName('CreatedDate').AsDateTime  := Now;
ds.FieldByName('Comments').AsString       := 'The quick brown fox jumped over the lazy dog';
ds.FieldByName('Quantity').AsFloat        := 19809.32; //imperial gallons
ds.FieldByName('InvoiceTotal').AsCurrency := 99.95; //GBP
ds.Post;

//Add another row of values - with an array of values all at once
ds.AppendRecord([1784, 'Steven Gates', Now, '//no comment', 1292, 19.25]);

You can also edit existing data:

ds.First;
ds.Edit;
ds.FieldByName('InvoiceNumber').AsInteger := 1786;

You can then use TDataSource to bind it to the TADODataSet and use data aware controls if needed linked to the TDataSource.

kbmMemTable CodeGear Edition which you can download for free as part of kbmMW CodeGear Edition, after signing up at https://portal.components4developers.com (ignore cert. errors if any occur.. the site is valid).

kbmMemTable CodeGear Edition contains the most feature rich in memory table for Delphi.. for free. It even contains:

  • SQL support advanced high performance indexes filtering bookmarks
  • dataset interchange with other dataset sources and destinations
  • master/detail multiple cursors (and separate filters and indexes) to
  • the physically same data very high performance versioning and
  • tracking of datachanges including the ability to resolve those
  • changes to someplace else via deltahandlers
  • plus hundreds more features and goodies in the product

If you need source kbmMemTable Standard Edition is available, and if you need the best performance you can find in a Delphi memory dataset, you can get kbmMemTable Professional Edition as a bundled part of kbmMW Professional Edition and kbmMW Enterprise Edition.

best regards Kim Madsen www.components4developers.com

JVCL has TjvMemoryData which supports random access to rows and fields. It is a bit more flexible than Delphi's own TClientDataSet.

There is an excellent series from Cary Jensen comparing ClientDataSets and DataTables: In-Memory DataSets: ClientDataSet and .NET DataTable Compared: Part 1 Overview

A free (for personal use) in-memory database table is available from AidAim

SQLMemTable is a fully functional in-memory database system; it includes database, table, query and batch move components as well as useful utility (with source code), demos and comprehensive help. SQLMemTable does not require BDE or any external drivers and has small footprint.

Another free (open source) component is TxQuery (MPL)

TxQuery component is a TDataSet descendant component that can be used to query one or more TDataSet descendant components using SQL statements

Data Storage Engine in AnyDAC. In general, it is ADO.NET v 1, but for native code. It may be used together with TADMemTable.

PS: AnyDAC is a commercial product.

The goal is to have a purely in-memory TDataSet. The issue with TClientDataSet (aside from the bugs), is that you will take a dependancy on a DLL that customer won't have on their computer. (Meaning you have a ship a dll dongle).

Fortunately Microsoft already created a client-side, in-memory, native equivalent of a DataTable: the ADO Recordset.

You can make your ADO Recordset, give it fields, and then wrap it in a TADODataSet so it descends from the canonical Delphi TDataSet (or you can just use the ADO Recordset object directly).

var
    rs: Recordset;

//Use ADO Recordset to hold our in-memory table
rs := CoRecordset.Create;
rs.CursorLocation := adUseClient; //default is adUseServer

Now that you have the recordset, you define fields:

//add our fields
rs.Fields.Append('InvoiceNumber', adInteger,      0,   adFldUpdatable, EmptyParam);
rs.Fields.Append('CustomerName',  adVarWChar,     200, adFldUpdatable, EmptyParam);
rs.Fields.Append('CreatedDate',   adDBTimeStamp,  0,   adFldUpdatable, EmptyParam);
rs.Fields.Append('Comments',      adLongVarWChar, -1,  adFldUpdatable, EmptyParam);
rs.Fields.Append('Quantity',      adDouble,       0,   adFldUpdatable, EmptyParam);
rs.Fields.Append('InvoiceTotal',  adCurrency,     0,   adFldUpdatable, EmptyParam);

You also have to Open the recordset to materialize the fields:

var
   o: OleVariant;

//It's impossible in Delphi to omit parameters. So we do it the late-binding IDispatch way
//  rs.Open(EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam);
o := (rs as IDispatch);
o.Open;

You have your empty in-memory table. Now you can add data rows:

//Add a row of values - the easy way
rs.AddNew(EmptyParam, EmptyParam); //moves cursor to newly added row
rs.Fields['InvoiceNumber'].Value := 1783;
rs.Fields['CustomerName'].Value  := 'Hubert Farnsworth';
rs.Fields['CreatedDate'].Value   := Now;
rs.Fields['Comments'].Value      := 'The quick brown fox jumped over the lazy dog';
rs.Fields['Quantity'].Value      := 19809.32; //imperial gallons
rs.Fields['InvoiceTotal'].Value  := 99.95; //GBP

//Add another row of values - you can add by single value
rs.AddNew('InvoiceNumber', 1784);

//Add another row of values - you can add by field names
rs.AddNew(VarArrayOf(['InvoiceNumber', 'InvoiceTotal']), VarArrayOf([1784, 22.37]));

//Add another row of values - you can add by ordinal index
rs.AddNew(VarArrayOf([0, 2]), VarArrayOf([1785, Now]));

//Move to the start of the Recordset, so it will be ready for the person using it.
if (not rs.BOF) or (not rs.EOF) then //You can't MoveFirst on a Recordset if the Recordset is empty. (It's throws an error instead of not throwing an error)
rs.MoveFirst;

And finally, we want a familiar TDataSet wrapper around it:

var
   dataset: TDataSet;      

//Wrap the recordset is a TDataSet descendant 
//that knows how to talk to an ADO recordset: the TADODataSet.
dataset := TADODataSet.Create(nil);
dataset.Recordset := rs;

So i can test it:

var 
   ds: TDataSet;
begin
   ds := CreateMemoryDataSet();
   ShowMessage(DataSetToMarkdown(ds));

and i get the expected in-memory data:

| InvoiceNumber | CustomerName      | CreatedDate          | Comments | Quantity | InvoiceTotal |
|---------------|-------------------|----------------------|----------|----------|--------------|
| 1783          | Hubert Farnsworth | 7/25/2017 3:32:21 PM | The quick brown fox jumped over the lazy dog | 19809.32 | 99.95 |
| 1784          |                   |                      |          |          |              |
| 1784          |                   |                      |          |          | 22.37        |
| 1785          |                   | 7/25/2017 3:32:22 PM |          |          |              |

You can also modify the in-memory values:

ds := CreateMemoryDataSet();    
ds.First;
ds.Edit;
ds.FieldByName('InvoiceNumber').AsInteger := 1786;
ShowMessage(DataSetToMarkdown(ds));

| InvoiceNumber | CustomerName      | CreatedDate          | Comments | Quantity | InvoiceTotal |
|---------------|-------------------|----------------------|----------|----------|--------------|
| 1786          | Hubert Farnsworth | 7/25/2017 3:32:21 PM | The quick brown fox jumped over the lazy dog | 19809.32 | 99.95 |
| 1784          |                   |                      |          |          |              |
| 1784          |                   |                      |          |          | 22.37        |
| 1785          |                   | 7/25/2017 3:32:22 PM |          |          |              |

You may be interested in TECDataset (EverClassy Dataset) from Inovativa (http://www.inovativa.com.br/public), which is an in-memory dataset that can be populated with objects of any class.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top