gpt4 book ai didi

sql-server - 为什么 FireDAC 忽略索引名称?

转载 作者:行者123 更新时间:2023-12-03 15:51:22 26 4
gpt4 key购买 nike

我正在尝试使用 FireDAC 在 SQL Server 数据库中创建表。但是,FireDAC 没有使用我提供的索引名称,而是使用了错误的索引名称,从而引发异常并且不会创建表。 我做错了什么吗?如果没有,有解决方法吗?

请注意,我对 TableName 使用有效的数据库架构名称 cnf我特别需要在架构中创建表

最简单的测试用例:

var
Connection: TFDConnection;
Table: TFDTable;
begin
Connection := TFDConnection.Create(nil);
Table := TFDTable.Create(nil);
try
Connection.Params.Add ('DriverID=MSSQL');
Connection.Params.Add ('OSAuthent=No');
Connection.Params.Add ('User_Name=sa');
Connection.Params.Add ('Password=XXXXXX');
Connection.Params.Add ('Server=DAVE-DELL\MSSQLSERVER2016');
Connection.Params.Add ('Database=PROJECT_DB');
Connection.Params.Add ('MARS=No');

Connection.Open;
Table.Connection := Connection;

Table.TableName := 'cnf.TestTable';
Table.FieldDefs.Add ('TableID', ftAutoInc, 0, true);
Table.FieldDefs.Add ('Field1', ftInteger, 0, true);
Table.FieldDefs.Add ('Field2', ftstring, 100, true);

Table.IndexDefs.Add ('PK_XYZ', 'TableID', [ixPrimary]); // should use this index name!

Table.CreateTable (true);

finally
Table.Free;
Connection.Free;
end;

end;

引发异常:

[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near '.'.

运行 SQL Server Profiler 显示 FireDAC 正在尝试使用以下 SQL 代码创建索引:

ALTER TABLE temp.TestTable ADD CONSTRAINT [cnf].[PK_TestTable] PRIMARY KEY (TableID)

当然,[cnf].[PK_TestTable] 在 T-SQL 中不是有效的索引名称,这是问题的关键。

  • 如果删除行 Table.IndexDefs.Add,则表会正确创建,但没有索引。
  • 如果我用以下内容替换该行,则会出现相同的问题:

    with Table.IndexDefs.AddIndexDef do begin
    Name := 'PK_XYZ';
    Options := [ixPrimary];
    Fields := 'TableID';
    end;
  • 如果我用以下内容替换设置表名称,则会出现相同的问题:

    Table.TableName := 'TestTable';
    Table.SchemaName := 'cnf';

为什么它使用它自己的(错误的)索引名称,而不是我给它的名称?(即PK_XYZ)

  • Embarcadero® Delphi 10.1 柏林版本 24.0.25048.9432
  • SQL Server 2016 (SP2-CU4) - 13.0.5233.0 (X64)

最佳答案

Am I doing something wrong?
Why is it using it's own (wrong) index name, instead of the name I gave it?

你似乎做的一切都恰到好处。问题出在生成的 SQL 命令上,正如您所追踪到的那样。 SQL Server doesn't allow schema name in constraint name使用 ALTER TABLE 添加约束时。通过这种方式创建的约束会自动成为相关表架构的一部分,但是稍后在引用约束时应使用架构名称:

SELECT OBJECT_ID('cnf.PK_XYZ')

现在哪里出了问题? FireDAC 使用 TFDPhysCommandGenerator 及其祖先为特定 DBMS 生成 SQL 命令。对 CreateTable 方法的调用会导致对 TFDPhysCommandGenerator.GetCreatePrimaryKey 的调用,该函数负责为主键生成 SQL。它还包含以下代码:

sTab := GetFrom;
FConnMeta.DecodeObjName(sTab, rName, nil, [doUnquote]);
rName.FObject := 'PK_' + rName.FObject;
Result := 'ALTER TABLE ' + sTab + ' ADD CONSTRAINT ' +
FConnMeta.EncodeObjName(rName, nil, [eoQuote, eoNormalize]) + ' PRIMARY KEY (';

此代码的作用是,它采用完全限定的表名称 (sTab) 将其 (DecodeObjName) 拆分为多个部分 (rName)将 'PK_' 添加到表名称中,并将各部分 (EncodeObjName) 连接回完全限定名称,然后将其用作主键的约束名称。现在我们可以清楚地看到命令生成器忽略您的索引名称并生成错误的 T-SQL。这可能是一个错误,也可能只是一个不受支持的功能。 EMBT 必须就此做出决定。我建议将其报告为错误。

Is there a work-around?

是的,您可以 Hook 有问题的方法,也可以在您自己的派生类中重写它。这些实现都不是微不足道的,由于法律问题,我不会在这里扩展它,因为我必须复制原始的 FireDAC 代码。

至于语法错误,在 DecodeObjName 之后将这些行添加到“TFDPhysCommandGenerator.GetCreatePrimaryKey”实现中可以解决问题:

rName.FCatalog := '';
rName.FSchema := '';
rName.FBaseObject := '';
rName.FLink := '';

修复约束名称会比这更麻烦,因为该方法仅接收索引列名称作为参数,并且无法明显访问原始 IndexDefs ,您可以在其中使用索引名称作为主键约束名称。从那里访问索引名称还可以让您摆脱将表名称解码/编码为索引名称的情况。然而,这个过程对于除 SQL Server 之外的其他 DMBS 来说可能是必不可少的。

PS:如果所有问题中只有一半是这样写的......谢谢你提出这个精彩的问题。

关于sql-server - 为什么 FireDAC 忽略索引名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56841177/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com