Delphi数据库默认值错误

时间:2016-01-31 14:26:43

标签: sql-server delphi adodb tadoquery tdataset

(SQL Server 2012,Delphi XE2,DataSet,DBGrid和adoquery)

我有一个包含这些列的简单表:

id entering, exiting, description

enteringexiting字段获取默认值0

创建新记录时的这些默认值不会出现在Delphi中。假设我们在夏季只有5个描述字段到字段。录音时不成问题。正常şartlarda不会出现短缺。您可以继续操作其他记录。

但是输入你添加的值只是进入该字段并不是什么新鲜事,并且在尝试在记录中看不到的过程中会发生错误。 0似乎已在关闭区域中打开,不再是错误。

很少出现这些默认值而不是错误。

我想知道我是如何解决这个问题的?

1 个答案:

答案 0 :(得分:0)

如果您的问题是如何从服务器获取默认列值,则下面的代码显示了两种执行此操作的方法,其中服务器是MS Sql Server,以及如何通过其{提供它们到表中的新行。 {1}}事件。 OnNewRecord是您应该用于在插入记录时设置字段值的数据集事件。

为了最大限度地减少误解的可能性,代码应该是自包含的:它创建一个新表,其中包含一个Identity列和另外三个具有默认值的表,然后使用两种不同的方法向其中添加数据行

注意: Delphi的TField及其后代具有OnNewRecord属性,将其设置为AutoGenerateValue 假设以检索默认列/来自服务器的字段值。在Delphi7时代,执行此操作的服务器端功能是AFAIK仅在DBTables单元中为长期过时的BDE实现。特别是Delphi的ADO数据集类型不支持它。我没有检查arDefault是否适用于其他更新的Delphi版本和数据集类型。

另外,请注意创建表的Sql语句之前调用DROP TABLE,并且为了避免在第一次执行时出错,您需要临时注释掉DROP TABLE部分。

代码:

AutoGenerateValue

上面的代码使用第二种获取列默认值的方法,方法是从服务器的数据库模式中检索它们。要使用此代码, 更改OnNewRecord代码以引用unit adodefaultsu; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, DBCtrls, Grids, DBGrids, DB, ADODB, Variants, StdCtrls; type TForm1 = class(TForm) ADOConnection1: TADOConnection; ADOQuery1: TADOQuery; DataSource1: TDataSource; DBGrid1: TDBGrid; DBNavigator1: TDBNavigator; Button1: TButton; ADOQuery2: TADOQuery; ADOQuery1id: TAutoIncField; ADOQuery1f1: TIntegerField; ADOQuery1f2: TIntegerField; ADOQuery1description: TStringField; DataSource2: TDataSource; DBGrid2: TDBGrid; ADODataSet1: TADODataSet; procedure FormCreate(Sender: TObject); procedure ADOQuery1NewRecord(DataSet: TDataSet); procedure Button1Click(Sender: TObject); private function GetColumnDefault(Field: TField): Variant; function GetColumnDefault2(Field: TField): Variant; public procedure CreateAndOpenTable; end; var Form1: TForm1; implementation {$R *.DFM} const scSqlCreateTable = 'DROP TABLE Table1;'#13#10 + 'CREATE TABLE [dbo].[Table1]('#13#10 + ' [id] [int] IDENTITY(1,1) NOT NULL,'#13#10 + ' [f1] [int] NOT NULL CONSTRAINT [DF_Table1_f1] DEFAULT ((1)),'#13#10 + ' [f2] [int] NOT NULL CONSTRAINT [DF_Table1_f2] DEFAULT ((2)),'#13#10 + ' [description] [varchar](40) default('''')'#13#10 + ') ON [PRIMARY]'; scSqlInsertRow = 'INSERT table1 (f1, description) VALUES(5, ''first'')'; scSqlSelect = 'select * from table1'; scSqlGetColumnDefault = 'SELECT object_definition(default_object_id) AS definition'#13#10 + 'FROM sys.columns'#13#10 + 'WHERE name =''%s'''#13#10 + 'AND object_id = object_id(''dbo.%s'')'; procedure TForm1.FormCreate(Sender: TObject); begin if not AdoDataSet1.Active then AdoConnection1.OpenSchema(siColumns, VarArrayOf(['MATest', 'dbo', 'Table1']), EmptyParam, AdoDataSet1); end; procedure TForm1.Button1Click(Sender: TObject); begin CreateAndOpenTable; end; function ExtractDefaultValue(Field : TField; const Input : String) : String; begin // The Input value is the default value for the column, surrounded by two // sets of parentheses and, in the case of a Char column, by leading and // trailing single-quote characters Result := Input; // remove leading and trailing parentheses while (Result <> '') and (Result[1] = '(') do Result := Copy(Result, 2, Length(Result) - 2); // for string fields, remove leading and trailing single-quotes if Field.DataType in [ftString] then begin if (Result <> '') and (Result[1] = '''') then Result := Copy(Result, 2, Length(Result) - 2); end; end; function TForm1.GetColumnDefault(Field : TField) : Variant; var Sql : String; sValue : String; begin try // First, contruct and execute a query to retrieve the default value // for the Field's server column Sql := Format(scSqlGetColumnDefault, [Field.FieldName, 'Table1']); if AdoQuery2.Active then AdoQuery2.Close; AdoQuery2.Sql.Text := Sql; AdoQuery2.Open; // WARNING: The following code has only been tested with Int and VarChar() columns // and may require extra code for other column types sValue := AdoQuery2.Fields[0].AsString; Result := ExtractDefaultValue(Field, sValue); Field.Value := Result; finally AdoQuery2.Close; end; end; function TForm1.GetColumnDefault2(Field : TField) : Variant; var Sql : String; sValue : String; begin // First, open the schema for the server via the AdoConnection if not AdoDataSet1.Active then AdoConnection1.OpenSchema(siColumns, VarArrayOf(['MATest', 'dbo', 'Table1']), EmptyParam, AdoDataSet1); // WARNING: The following code has only been tested with Int and VarChar() columns // and may require extra code for other column types if not AdoDataSet1.Locate('COLUMN_NAME', Field.FieldName, [loCaseInsensitive]) then raise Exception.CreateFmt('GetColumnDefault2: Field % not found in schema', [Field.FieldName]); sValue := AdoDataSet1.FieldByName('COLUMN_DEFAULT').AsString; Result := ExtractDefaultValue(Field, sValue); Field.Value := Result; end; procedure TForm1.ADOQuery1NewRecord(DataSet: TDataSet); begin GetColumnDefault2(DataSet.FieldByName('f1')); GetColumnDefault2(DataSet.FieldByName('f2')); GetColumnDefault2(DataSet.FieldByName('description')); end; procedure TForm1.CreateAndOpenTable; begin AdoQuery1.SQL.Text := scSqlCreateTable; AdoQuery1.ExecSQL; AdoQuery1.SQL.Text := scSqlInsertRow; AdoQuery1.ExecSQL; AdoQuery1.Sql.Text := scSqlSelect; AdoQuery1.Open; // Next, insert a second row by the equivalent of clicking the // DbNavigator's '+' button AdoQuery1.Insert; AdoQuery1.Post; end; end. 而不是GetColumnDefault2。这种方法可能更可取,因为它只涉及获取默认值一次,然后AdoDataSet1缓存它们。

上面的代码是为Delphi7编写的,但也适用于更高版本。

如果这回答了您的问题,我会尝试编辑您的问题以使其更清晰。

最后,没有任何涉及在客户端应用程序中更改Sql的Delphi答案似乎已经完成,但没有警告Sql注入的风险 - 请参阅https://en.wikipedia.org/wiki/Sql_injection