如何编辑数据集?

短版

我怎么称呼:

dataset1.FieldByName(fieldName).AsString := 'Something';

并且有效吗?

长版

我有一个DataSet

var
    ds: tdataset;

    ds := GetsomeSortOfDatasetfromSomewhere();

此数据集将被导出(例如导出到Excel,cSV,TSV,Markdown,HTML,XML):

Exportdataset(ds);

,导出将包含所有列和所有行:

| username | Fullname                |
|----------|-------------------------|
| ian      | IAN BOYD                |
| MartynA  | MARTIN                  |
| ngal     | NASREDDINE GALFOUT      |
| uewr     | UWE RAABE               |

现在,我想在进行其他操作之前修改内存中每行的Fullname字段(即,它永远不会返回数据库,我不知道在哪里它来自,可能不是来自数据库):

while not ds.EOF do
begin
    ds.FieldByName('Fullname').AsString := FormatNamePrettyLike(ds.FieldByName('Fullname').AsString;
    ds.Next;
end;

尝试修改字段会产生异常:

Dataset not in edit or insert mode

解决方案是将数据集克隆到内存TClientDataset

///<summary>Clones a dataset into a TClientdataset; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: tdataset): tdataset; //tdataset > TCustomClientdataset > TClientdataset
var
    tempProvider: tdatasetProvider;
    data: OleVariant;
    ds: TClientdataset;
begin
    tempProvider := tdatasetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientdataset.Create(nil);
    ds.Data := data;

    Result := ds;
end;

哪个给出了更大的代码:

var
   ds: tdataset;
   dsEditable: tdataset;

   ds := GetDataSomeOfSomeSortFromSomewhere();

   //Clone to dataset to an in-memory dataset so we can modify it.
   dsEditable := CloneDataSet(ds);
   ds.Free;
   ds := edEditable;

   while not ds.EOF do
   begin
       ds.FieldByName('Fullname').AsString := FormatNamePrettyLike(ds.FieldByName('Fullname').AsString;
       ds.Next;
    end;

但这会导致错误:

Dataset not in edit or insert mode

解决方案是put the dataset in edit mode

//The in-memory Clientdataset won't be editable until you mark it editable.
ds.Edit; 

///<summary>Clones a dataset into a TClientdataset; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: tdataset): tdataset; //tdataset > TCustomClientdataset > TClientdataset
var
    tempProvider: tdatasetProvider;
    data: OleVariant;
    ds: TClientdataset;
begin
    tempProvider := tdatasetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientdataset.Create(nil);
    ds.Data := data;

    //The in-memory Clientdataset won't be editable until you mark it editable.
    ds.Edit;

    Result := ds;
end;

现在重复锻炼会出现错误:

字段Fullname无法修改。

解决方案是set Field.ReadOnly to false

//Even after marking the in-memory data-set as editable,you still can't edit it 
//until you mark all fields as editable.
for i := 0 to ds.FieldCount-1 do
   ds.Fields[i].ReadOnly := False;

///<summary>Clones a dataset into a TClientdataset; which is an editable in-memory DataSet.</summary>
function CloneDataSet(dsSource: tdataset): tdataset; //tdataset > TCustomClientdataset > TClientdataset
var
    tempProvider: tdatasetProvider;
    data: OleVariant;
    ds: TClientdataset;
begin
    tempProvider := tdatasetProvider.Create(nil);
    try
        tempProvider.DataSet := dsSource;
        data := tempProvider.Data;
    finally
        tempProvider.Free;
    end;

    ds := TClientdataset.Create(nil);
    ds.Data := data;

    //The in-memory Clientdataset won't be editable until you mark it editable.
    ds.Edit;

    //Even after marking the in-memory data-set as editable,you still can't edit it 
    //until you mark all fields as editable.
    for i := 0 to ds.FieldCount-1 do
        ds.Fields[i].ReadOnly := False;

    Result := ds;
end;

重复练习会出现错误:

尝试修改只读字段。

所以我放弃了。如何编辑数据集字段?

所有克隆的内存TCustomClientdataset内容都在这里;我只想在客户端上对其进行编辑以用于显示。

奖励聊天

很明显,我无法在数据集中添加新列:

| username | Fullname                | PrettyFullname     |
|----------|-------------------------|--------------------|
| ian      | IAN BOYD                | Ian Boyd           |
| MartynA  | MARTIN                  | Martin             |
| ngal     | NASREDDINE GALFOUT      | Nasreddine Galfout |
| uewr     | UWE RAABE               | Uwe Raabe          |

很明显,我无法将事件处理程序附加到数据集:

  • 因为当数据集传递到链中的下一个人(例如线程),并且原始形式被释放时,数据处理程序将无效
  • 这也不是我要的;关于修改数据集的内容
  • 值的更新会影响其他系统(例如数据库,Web服务等)。我希望更改一次,然后输入数据集
marish 回答:如何编辑数据集?

假设我实际上正确地理解了您的问题,可以归结为将 FullName 的字段内容更改为一些漂亮的格式的字符串以供显示。

因此,由于您不想更改实际的字段内容,所以最好的选择是在字段 OnGetText 事件中。适合您任务的事件处理程序可能如下所示:

procedure TMyClass.MakeFullNamePrettyGetText(Sender: TField; var Text: string; DisplayText: Boolean);
begin
  Text := FormatNamePrettyLike(Sender.AsString);
end;

现在,您必须将该事件处理程序连接到该字段。在处理动态字段时,每次打开数据集后都必须这样做:

qry.FieldByName('Fullname').OnGetText := MakeFullNamePrettyGetText;

只要发生在声明事件的类之外,您就需要在事件名称前加上 TMyClass (或您可以称之为的任何类)的类实例。

,

下面是从Sql Server编辑数据的完全独立的示例 使用ADO + TClientDataSet。所有组件都只需从面板中删除 到表单上,然后在SetUp过程中的代码中设置所有必要的属性。

在每个步骤中,我都尝试使用最简单的代码来完成这项工作,以免模糊不清 CDS + TDataSetProvider如何编辑数据的优雅简洁性。请参阅Provider.Pas中的TSqlResolver.GenUpdateSql方法,以了解如何 它生成DSP发出更新所需的Sql UPDATE语句 服务器表中的数据。这些通过特殊类型发送到服务器 DSP用来在其CDS和源数据集之间进行通信的数据包的数量。

希望代码是不言自明的,并且注释最少。

如您所见,

绝对不会摆弄CDS的TFields的属性 有必要的。顺便说一句,我是作为VCL应用而不是仅通过控制台来完成此操作的 因此,从视觉上确认一切都正常是很简单的。

作为一种最低公分母,我使用了D7。在后Unicode Delphi中, 服务器上的FullName字段将为NVarChar类型,而字符串字段类型为 CDS会自动调整。

type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    CDS1: TClientDataSet;
    DataSetProvider1: TDataSetProvider;
    DBGrid1: TDBGrid;
    procedure FormCreate(Sender: TObject);
  private
    procedure SetUp;
  end;
[...]
const
  scConnString = 'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=MATest;Data Source=MAT430\ss2014';
  scCreateTable = 'create table TestTable(ID int not null primary key,FullName varchar(40))';
  scSelectAll = 'select * from TestTable';

procedure TForm1.SetUp;
begin
  AdoConnection1.ConnectionString := scConnString;

{.$define CreateTable}  // to do a one-off creation of the server table and data
{$ifdef CreateTable}
  AdoConnection1.Execute(scCreateTable);
{$endif}

  AdoQuery1.Connection := AdoConnection1;
  AdoQuery1.SQL.Text := scSelectAll;

{$ifdef CreateTable}
  AdoQuery1.Open;
  AdoQuery1.InsertRecord([1,'Joe Blow']);
  AdoQuery1.Close;                             
{$endif}

  DataSetProvider1.DataSet := AdoQuery1;
  CDS1.ProviderName := 'DataSetProvider1';
  DataSource1.DataSet := CDS1;
  DBGrid1.DataSource := DataSource1;

  CDS1.Open;
  CDS1.Edit;
  CDS1.FieldByName('FullName').AsString := 'Mr ' + CDS1.FieldByName('FullName').AsString;
  CDS1.Post;

  //  Post the chamges back to the server table if desired
  CDS1.ApplyUpdates(0);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetUp;
end;

end.

附录注释中提出的一点是,可以通过使用计算所得的字段有效地美化FullName字段。我无法立即想到在代码中进行设置的方法 但基本上我会这样做:

  • 在CDS上,设置持久性TField(从CDS的上下文菜单中)。
  • 在“字段”编辑器中,添加一个类型为fkInternalCalc的计算字段。对于CDS,这 比fkCalculated更好用,因为fkInternalCalc可以包含在CDS的索引中
  • 执行CDS的OnCalcFields事件中所需的任何计算。没有遍历 那么,就必须使用CDS记录(在您的代码中)进行计算,因为CDS会按照自己的意图进行计算。

更新事实证明,将fkInternal calc字段完全以代码形式添加到CDS是很简单的,即使有些琐事。诀窍是从服务器检索FieldDef,将其保留在CDS中,然后重新创建其TField,然后重新打开它。像这样:

  CDS1.Open;
  CDS1.StoreDefs := True;
  CDS1.Close;
  for i := 0 to CDS1.FieldDefs.Count - 1 do begin
    Field := CDS1.FieldDefs[i].CreateField(Self,Nil,CDS1.FieldDefs[i].DisplayName);
  end;
  Field := TStringField.Create(Self);
  Field.Size := CDS1.FieldByName('FullName').Size;
  Field.FieldKind := fkInternalCalc;
  Field.FieldName := 'EnhFullName';
  Field.DataSet := CDS1;

  CDS1.Open;
本文链接:https://www.f2er.com/2655686.html

大家都在问