-1

我想创建一个新的 mdb 文件,其中包含基于以前存在的表的结构的表。我知道我可以用newTable.FieldDefs.Add()它在循环中一个一个地重新创建字段。但是由于已经有一个 oldTable 完全存放了正确的FieldDefs,这似乎非常不雅。我一直在寻找单语句解决方案!

我发现它newTable.FieldDefs.Assign(oldTable.FieldDefs)可以编译(并运行)而没有错误,但它留下newTable了零定义的字段。这使我错误地得出结论,即我不理解该语句的功能。(后来我发现它只有在oldTable.open没有发生时才会失败,当数据库不可用时不会发生这种情况,即使FieldDefs已经将其设置为 Persistent 并且在 Object Inspector 中清晰可见)

这是我经过一番调查后的原始代码:

procedure TForm2.Button1Click(Sender: TObject);
var
  fname: string;
  Table: TFDTable;
  FDConn: TFDConnection;

begin
  fname := 'C:\ProgramData\mymdb.mdb';
  if FileExists(fname) then DeleteFile(fname);

  { Make new file for Table }
  FDMSAccessService1.Database := fname;
  FDMSAccessService1.DBVersion := avAccess2000;
  FDMSAccessService1.CreateDB;

  { Connect to new file }
  FDConn := TFDConnection.Create(nil);
  FDConn.Params.Database := fname;
  FDConn.Params.DriverID := 'MSAcc';
  FDConn.Connected := true;

  { Set up new Table using old table's structure }
  Table := TFDTable.Create(nil);
  try
    { ADOTable1 has been linked to an existing table in a prior
      database with Field Defs made Persistent using the Fields
      Editor in the Object Inspector. That database will not be
      available in my actual use scenario }
    try
      ADOTable1.open; // Throws exception when database file not found
    except
    end;
    Table.Connection := FDConn;
    { specify table name }
    Table.TableName := ADOTable1.TableName;
    Table.FieldDefs.Assign(ADOTable1.FieldDefs);  // No errors reported
    ShowMessageFmt('New Table %s has %d fields',[Table.TableName,
      Table.FieldDefs.Count]);
    { Reports correct TableName but "0 fields" with table not open
      (i.e. file not found). Reports "23 fields" with table open }
    { Set Table definition into new mdb file }
    Table.CreateTable(False); // Throws exception when 0 fields found
  finally
    Table.Free;
  end;

end;

事实证明,解决方案是使用最初链接到同一个旧数据库的 ClientDataSet 而不是 ADOTable。请参阅我的回答中的以下工作解决方案。

编辑:最后一点。我曾希望使用这种 FireDAC 方法,如此处所示,来解决缺少TADOTable.CreateTable方法的问题。唉,尽管上面和下面的“解决方案”确实可以创建一个新TADOTable的 ,但该表的字段定义并不是原始表的忠实副本。可能有无数TFDTable选项的组合可以解决这个问题,但我无法发现它,所以我恢复使用 SQL 创建我的 ADO 表。

4

1 回答 1

1

感谢@Ken White(不幸删除)的指针,我现在认为我有一个解决方案来解决我原来的问题,即将字段 defs 从旧表克隆到新创建的数据库中。我最初的问题源于这样一个事实,即如果表未“打开”(即连接到相关数据库),表的 FieldDefs 函数显然不会返回实际存储的字段数据。由于我的使用场景没有可用的有效数据库,我无法“打开”表。但是,ClientDataSets 具有“StoreDefs”的附加选项以及“Fetch Params”和“Assign Local Data”的编辑器选项。保存这些设置后,ClientDataSet 呈现其 FieldDefs 属性而不是“打开”。使用这种方法,我似乎可以将存储的字段 defs 克隆到一个新表中,而无需当前有效的数据库来读取它们。再次感谢,肯,你救了我很多剩下的头发!我当然希望 Embarcadero 在合理化他们的帮助文件方面做得更好。他们从 Rio 的默认安装中删除了 BDE,同时仍然在他们的帮助文件讨论中指出将 Access 表创建为其 TTable 类型作为创建新表的方式,然后从不指向他们继续使用的 FireDAC(或其他地方)中的等效功能支持。因为这个“疏忽”,我浪费了很多时间!我当然希望 Embarcadero 在合理化他们的帮助文件方面做得更好。他们从 Rio 的默认安装中删除了 BDE,同时仍然在他们的帮助文件讨论中指出将 Access 表创建为其 TTable 类型作为创建新表的方式,然后从不指向他们继续使用的 FireDAC(或其他地方)中的等效功能支持。因为这个“疏忽”,我浪费了很多时间!我当然希望 Embarcadero 在合理化他们的帮助文件方面做得更好。他们从 Rio 的默认安装中删除了 BDE,同时仍然在他们的帮助文件讨论中指出将 Access 表创建为其 TTable 类型作为创建新表的方式,然后从不指向他们继续使用的 FireDAC(或其他地方)中的等效功能支持。因为这个“疏忽”,我浪费了很多时间!

这是肯提示后我的工作代码:

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
fname: string;
Table: TFDTable;
FDConn: TFDConnection;

begin
  fname := 'C:\ProgramData\mymdb.mdb';
  if FileExists(fname) then DeleteFile(fname);
  FDMSAccessService1.Database := fname;
  FDMSAccessService1.DBVersion := avAccess2000;
  FDMSAccessService1.CreateDB;

  FDConn := TFDConnection.Create(nil);
  FDConn.Params.Database := fname;
  FDConn.Params.DriverID := 'MSAcc';
  FDConn.Connected := true;

  Table := TFDTable.Create(nil);
  try
    Table.Connection := FDConn;
    { specify table name }
    Table.TableName := 'ATable';
    { The existingClientDataSet has been linked to a table in the
      prior, no longer valid, database using StoreDefs, Fetch Params,
      and Assign Local Data in the Object Inspector }
    Table.FieldDefs.Assign(existingClientDataSet.FieldDefs);
    ShowMessageFmt('New Table has %d fields', [Table.FieldDefs.Count]);
    Table.CreateTable(False);
  finally
    Table.Free;
  end;
于 2019-04-13T03:53:49.820 回答