主题:主从表更新
主从表两种模式
查询式:从表的查询语句中加外键参数,如 pid=:id. 这种主表移动时,从表会重新查询数据库.
区间式:设置从表的indexfieldnames=pid, masterfields = id. 这种会把所有数据读入从表,主表移动时,从表设置显示过滤.
缓存更新:cacheupdates = true. 这种必须设置为区间式.不然主表一移动,从表修改的数据就没了.
从表: FetchOptions.DetailCascade=true, 主表提交时,主键更新,从表会自动更新外键值.保持与主表的连接.
从表: DetailServerCascade=true, 与.DetailCascade一同使用,单设置 DetailServerCascade 无效. 用于控制是否级联把从表的更新提交到服务器. ^-^一般用不到.必竟很少有没事就去修改主表主键的.
- UpdatesPending 更新中 - returns 回报True 没错, if the change log is not empty; 如果更改日志不为空;
- ChangeCount 更改计数 - returns the total number of changes; - 返回更改的总数;
- UpdateStatus 更新状态 - returns the change kind for the current record; - 返回当前记录的变更类型;
- FilterChanges 滤镜改变 - allows to filter records by the modification kinds. - 允许根据修改类型对记录进行过滤
To revert the existing changes, use the following properties and methods:
若要恢复现有更改,请使用以下属性和方法:
- SavePoint – sets/gets the current change log state; - 设置/获取当前更改日志状态;
- RevertRecord 恢复记录 – reverts the current record to it previous (original) state; - 将当前记录恢复为以前(原始)的状态;
- UndoLastChange – jumps to the last modified record and reverts it to its previous (original) state; 跳转到最后修改的记录,并将其恢复到以前(原始)的状态;
- CancelUpdates 取消更新 – reverts all records in the change log. - 恢复更改日志中的所有记录
注意: 在缓存更新模式中,下列方法和属性用于更新日志:
- The 那个Data 百科 property includes all records, even deleted, and their changes; 属性包括所有记录、甚至删除的记录及其更改;
- The 那个Delta 三角洲部队 property returns the deleted, inserted or updated records in the updates journal; 属性返回更新日记中已删除、插入或更新的记录;
- The 那个CopyRecord 复制记录 and 还有CopyDataSet methods create new changes and do not copy change journal; 方法创建新的变更,不复制变更日志;
- LoadFromStream, LoadFromFile, SaveToStream 保存 ToStream, and 还有SaveToFile 保存到文件 load / save data with updates journal. 使用更新日志加载/保存数据.
-
在缓存更新模式中,如果更新日志中有更改,某些方法或属性设置将引发异常。它们必须被承诺或取消。这些是:
- Refresh 刷新;
- setting 设定CachedUpdates 缓存更新 to 到False 假的.
ApplyUpdate出错时处理:
var oErr: EFDException; ... if FDQuery1.ApplyUpdates > 0 then begin FDQuery1.FilterChanges := [rtModified, rtInserted, rtDeleted, rtHasErrors]; try FDQuery1.First; while not FDQuery1.Eof do begin oErr := FDQuery1.RowError; if oErr <> nil then begin // process exception object ... end; FDQuery1.Next; end; finally FDQuery1.FilterChanges := [rtUnmodified, rtModified, rtInserted]; end; end;
要禁用对列的更新,请pfInUpdate
从相应的TField.ProviderFlags属性中排除。
UpdateOptions.RefreshMode =rmOnDemand
控制列值的自动刷新,在插入或更新记录后可能由 DBMS 更改。插入记录后可能需要刷新的列如下:
- 自动递增列;
- 数据库计算列;
- 具有默认值的列;
- 行识别列;
- 时间戳列;
- 由触发器更新的列。
记录更新后可能需要刷新的列如下:
- 数据库计算列;
- 时间戳列;
- 由触发器更新的列。
根据 DBMS 功能,将生成额外的短语/命令,返回刷新的列值:
- Oracle、Firebird、PostgreSQL - 返回短语;
- DB2 - SELECT ... FROM FINAL TABLE 短语;
- SQL Server、SQL Anywhere、SQLite - 带有附加 SELECT 命令的 SQL 批处理;
- 否则 - 一个额外的 SELECT 命令。
有时将UpdateChangedFields设置为False可能会提高性能。并结合其他几个设置,如UpdateOptions.FastUpdates属性,它允许通过避免额外的查询并启用缓存生成的更新命令,在更新发布时获得更好的性能。
FastUpdates = True等价于:
- UpdateChangedFields = False ;
- 更新模式=
upWhereKeyOnly
; - 锁定模式=
lmNone
; - 刷新模式=
rmManual
; - CheckRequired =假。
以上内容参考:Update Command Generation (FireDAC) - RAD Studio
Caching Updates (FireDAC) - RAD Studio
Overriding Posting Updates (FireDAC) - RAD Studio
Specifying Update Table Name 指定更新表名称
In some cases, the application needs to specify an alternative DB table name, to which the updates will be posted. To do that, set UpdateOptions.UpdateTableName to a required table name.
在某些情况下,应用程序需要指定另一个 DB 表名,更新将发布到该表。为此,请设置 UpdateOptions。将 UpdateTableName 设置为所需的表名。
Specifying Update Column Names and Modes 指定更新列名称和模式
In some cases, the application needs to exclude columns from an updating SQL command. To do that, exclude pfInUpdate
from TField.ProviderFlags. And set TField.ReadOnly to prohibit the field value modification.
在某些情况下,应用程序需要从更新的 SQL 命令中排除列。为此,从 TField 中排除 pfInUpdate。提供者旗帜。设置 TField。ReadOnly 禁止修改字段值。
To specify alternative an DB column name, set TField.Origin to a required value.
若要指定其他 DB 列名,请将 TField.Origin 设置为所需的值。
Settings at Run Time 运行时设置
To specify the TFDUpdateSQL SQL commands at run time, the application should use XxxxSQL properties. To introduce references in an SQL to a specific column value, use the parameter markers:
若要在运行时指定 TFDUpdateSQLSQL 命令,应用程序应使用 XxxxSQL 属性。若要在 SQL 中引入对特定列值的引用,请使用参数标记:
- new column value - 新列值-:NEW_<column name> : NEW _ < column name >;
- old column value - 旧列值-:OLD_<column name> : OLD _ < column name >;
- current column value - 当前列值-:<column name> : < 列名 >.
These parameter values will be assigned automatically by FireDAC. Do not assign a value to them, because their values will be overridden. FireDAC will ignore parameters with other names.
这些参数值将由 FireDAC 自动分配。不要为它们赋值,因为它们的值将被重写。FireDAC 将忽略具有其他名称的参数。
The command parameters and command macros may be setup only at run time. To this purpose, you have to use the TFDUpdateSQL.Commands property, which returns references to the TFDCommand objects. For example:
命令参数和命令宏只能在运行时设置。为此,必须使用 TFDUpdateSQL.Command 属性,该属性返回对 TFDCommand 对象的引用。例如:
FDUpdateSQL1.InsertSQL.Text := 'insert into &tab (id, name) values (:new_id, :new_name)';
FDUpdateSQL1.Commands[arInsert].Macros[0].AsRaw := 'Orders';
Using OnUpdateRecord 使用 OnUpdateRecord
This event allows to completely override posting updates from a dataset. The event handler code can read the dataset fields properties:
此事件允许完全覆盖从数据集发布更新。事件处理程序代码可以读取数据集字段属性:
- OldValue - returns the original field value, as it was fetched or as it is after the last - 返回原始字段值,如取得的值或最后一个字段之后的值CommitUpdates 委员会最新情况 / CancelUpdates 取消更新 call; 电话;
- CurValue / Value 价值 - returns the current field value. - 返回当前字段值
Also, you can combine TFDUpdateSQL and OnUpdateRecord approaches to enable semi-automatic updates posting to different tables or databases.
此外,还可以将 TFDUpdateSQL 和 OnUpdateRecord 方法结合起来,以便能够半自动地将更新发送到不同的表或数据库。
For details, see the OnUpdateRecord event description and the FireDAC demos:
有关详细信息,请参阅 OnUpdateRecord 事件描述和 FireDAC 演示:
- TFDQuery OnUpdateRecord 更新记录查询
- FireDAC\Samples\Comp Layer\TFDUpdateSQL\Main FireDAC 示例组合层 TFDUpdateSQL 主
通过OnUpdateRecord是否可以获取新值?最好是直接从数据库读取新记录.这样最准确.因为除了自增字段外还有默认值字段计算字段等.
select a.*,b.* from a join b 这种查询更新需要手动处理. 因为更新可能设及到多个表.
以下是用两个TFdUpdateSqL来处理的关键代码.
完整示例:
FireDAC.TFDQuery.OnUpdateRecord Sample - RAD Studio Code Examples
procedure TfrmCachedUpdates.qryProductsUpdateRecord(ASender: TDataSet;
ARequest: TFDUpdateRequest; var AAction: TFDErrorAction;
AOptions: TFDUpdateRowOptions);
begin
// Categories and Products DB tables are related one-to-many.
// qryProducts.SQL is a join of Products and Categories tables.
// usProducts posts changes to Products table and usCategories
// to Categories one. At first, we post changes to Products
// (detail) table, at second to Categories (master) one.
if not (ARequest in [arLock, arUnlock]) then begin
usProducts.ConnectionName := qryProducts.ConnectionName;
usProducts.DataSet := qryProducts;
usProducts.Apply(ARequest, AAction, AOptions);
if AAction = eaApplied then begin
usCategories.ConnectionName := qryProducts.ConnectionName;
usCategories.DataSet := qryProducts;
usCategories.Apply(ARequest, AAction, AOptions);
end;
end;
AAction := eaApplied;
end;
当您运行应用程序时,单击Use Connection Definition组合框并选择一个选项以定义连接。当您选择组合框的一项时,将调用Open方法以打开与与此连接相关的架构适配器关联的所有数据集。然后,您将看到两个表,每个表中都有一个TDBGrid。两个TDBGrid都用于在表格网格中显示和操作数据集中的记录。填充TDBGrid 后,您可以与示例交互。以下每个按钮都实现了一个OnClick事件来执行下面描述的操作:
- 更改或编辑任何数据记录。然后OnDataChange事件使用ChangeCount属性显示更改日志中的更改次数。
- 与提供示例的按钮交互:
- SavePoint按钮使用SavePoint属性返回更改日志中的当前位置。
- RevertPoint按钮使更改日志返回到获取 SavePoint值时的状态。
- UndoLastChange按钮使用UndoLastChange方法取消架构适配器更改日志中的最后一个记录更改,并从更改日志中删除记录。
- CancelUpdates按钮使用CancelUpdates方法取消此模式适配器更改日志中所有记录的更改,并将它们从更改日志中删除。
- ApplyUpdates按钮使用 :
- ApplyUpdates方法将集中更改日志中所有记录的更改应用到数据库。
- CommitUpdates方法将此模式适配器更改日志中的所有记录标记为未修改并将它们从更改日志中删除。
关于宏的说明:
Preprocessing Command Text (FireDAC) - RAD Studio
- '!'--“字符串”替换模式。宏值将“按原样”直接替换到命令文本中,无需任何转换。
- '&'--“SQL”替换模式。宏值将根据宏数据类型使用目标 DBMS 语法规则进行替换。
Escape Sequences 逃逸序列
FireDAC has 5 types of escape sequences:
FireDAC 有5种转义序列:
- Allowing constant substitution. 允许常量替换
- Allowing identifier substitution. 允许标识符替换
- Conditional substitution. 条件置换
- LIKE operator escape sequence. 像操作符转义序列
- Scalar functions. 标量函数
The escape sequences are processed when ResourceOptions.EscapeExpand is True.
当 ResourceOptions.EscapeExpand 为 True 时,将处理转义序列。
The constant substitution escape sequences allow writing constants in command text, independent of the DBMS syntax and regional settings. The following table describes escape sequences expansion to DBMS syntax:
常量替换转义序列允许在命令文本中编写常量,与 DBMS 语法和区域设置无关。下表描述了转义序列扩展到 DBMS 语法的过程:
Format 格式 | Description 描述 |
---|---|
{e <number>} { e < number > } | Number constant. <number> must be specified with '.' as decimal separator. 数字常数。 < Number > 必须以’.’为小数点指定 For example: {e 123.7} -> 123,7 on MSAccess 例如: MSAccess 上的{ e 123.7}-> 123.7 |
{d <date>} { d < date > } | Date constant. <date> must be specified in 'yyyy-mm-dd' format. 日期常数。 < Date > 必须以‘ yyyy-mm-dd’格式指定 For example: {d 2004-08-30} -> TO_DATE('2004-08-30', 'yyyy-mm-dd') on Oracle. 例如: { d 2004-08-30}-> TO _ DATE (‘2004-08-30’,‘ yyyy-mm-dd’) on Oracle。 |
{t <time>} { t < time > } | Time constant. <time> must be specified in 'hh24:mi:ss' format. 时间常数。 < Time > 必须以‘ hh24: mi: ss’格式指定 For example: {t 14:30:00} -> CONVERT(DATETIME, '14:30:00', 114) on SQL Server 例如: { t 14:30:00}-> CONVERT (DATETIME,’14:30:00’,114) on SQL Server |
{dt <date & time>} { dt < date & time > } | Date and time constant. <date & time> must be in the above formats. 日期和时间常数。 < 日期和时间 > 必须采用上述格式 |
{l <boolean>} { l < boolean > } | Boolean constant. <boolean> is 布尔常数 < 布尔 > 是False 假的 or 或者True 没错. If DBMS supports Boolean data type, then the sequence expands to that type constant, otherwise it expands to numeric values 0 or 1. .如果数据库管理系统支持布尔,那么序列就会扩展为该类型常量,否则就会扩展为数值0或1 |
{s <string>} { s < string > } | String constant. <string> is a quoted or not quoted sequence of characters. 字符串常量。 < String > 是带引号或不带引号的字符序列 For example: {s Company '1st Coding'} -> 'Company 1st Coding' 例如: { s 公司的第一个编码}-> “公司的第一个编码” |
The identifier substitution escape sequence allows abstracting from DBMS-specific identifier quoting rules. For more details, see "Object Names". The syntax is:
标识符替换转义序列允许从特定于 DBMS 的标识符引用规则中抽象出来。有关详细信息,请参阅“对象名称”。语法是:
Format 格式 | Description 描述 |
---|---|
{id <identifier name>} { id < 标识符名称 > } | Expands to DBMS-specific quoted identifier syntax. 扩展到特定于 DBMS 的带引号标识符语法 For example: {id Order Details} -> “Order Details” on Oracle. 例如: { id Order Details }-> Oracle 上的“ Order Details”。 |
The escape function sequence allows abstracting from a DBMS-specific set of a built-in functions and their syntax. The syntax is:
转义函数序列允许从特定于 DBMS 的一组内置函数及其语法中抽象出来:
Format 格式 | Description 描述 |
---|---|
{fn <function name>(<arguments>)} { fn < 函数名 > (< 参数 >)} | The escape functions syntax and set is identical to the ODBC escape functions. In the subtopics, the FireDAC escape functions are listed. 转义函数的语法和设置与 ODBC 转义函数相同。在子主题中,列出了 FireDAC 转义函数 For example: SELECT * FROM MyTab WHERE Year = {fn YEAR({fn NOW()}} or SELECT * FROM MyTab WHERE Year = {YEAR({NOW()}} -> SELECT * FROM MyTab WHERE Year = TO_NUMBER(TO_CHAR(SYSDATE, 'YYYY')) on Oracle. 例如: SELECT * FROM MyTab WHERE YEAR = { fn YEAR ({ fn NOW ()}} or SELECT * FROM MyTab WHERE YEAR = { YEAR ({ NOW ()}}-> SELECT * FROM MyTab WHERE YEAR = TO _ Number (TO _ char (SYSDATE,‘ YYYY’)) on Oracle。 |
{<function name>(<arguments>)} { < 函数名 > (< 参数 >)} | The same as above. 和上面一样 |
Conditional Substitution 条件替换
Conditional substitution escape sequences allow to substitute text into command, depending on either a DBMS the application is connected to, or on a macro variable value. Beside different syntaxes, these constructions handle parameters and macros in different ways. Escape sequence syntaxes are:
条件替换转义序列允许将文本替换为命令,这取决于应用程序连接到的 DBMS 或宏变量值。除了不同的语法之外,这些构造还以不同的方式处理参数和宏。转义序列语法如下:
Format 格式 | Description 描述 |
---|---|
{iif (X1, Y1, …, XN, YN, YN+1) } { iif (X1,Y1,... ,XN,YN,YN + 1)} | Here Xi is either: 在这里,习要么是:
If neither of these conditions is met and YN+1 text is specified, then it will be substituted into command. Parameters and macros in either Xi and Yi will be created in the Params and Macros collection. 如果这两个条件都不满足,并且指定了 YN + 1文本,那么它将被替换为命令。将在 Params 和 Macros 集合中创建玺和 Yi 中的参数和宏。 |
{if x} y {fi} { if x } y { fi } | Here, X is either: 在这里,X 是:
Parameters and macros in Y will be created in the Params and Macros collection only if X is True. 只有当 X 为 True 时,才会在 Params 和 Macros 集合中创建 Y 中的参数和宏。 |