[英]How can I implement “writable calculated” fields in a TDataSet?
我需要在TDataSet中添加其他字段,这些字段在底层数据库中不存在,但可以从现有字段派生。 我可以轻松地使用caclulated字段做到这一点,并且完美无缺。
现在我想编辑这些字段并将更改的数据写回。 我可以反转计算以将数据写回现有字段,但DB控件只是不允许我编辑计算字段。
是否有任何方法可以让我这样做?
更新:好的,有关背景的更多细节。
数据集有一个blob字段,它是一个TBytes表示。 一些字节被识别为包含可以用现有DB编辑字段以方便的方式表示的信息。 但是,并非所有字节都是已知的,因此TBytes表示必须保持原样,以便通过另一个了解它的应用程序进行处理。 此应用程序还修改现有和插入新记录。
数据集中不同记录的TByte经常映射到不同的字段表示,尽管在数据集上设置过滤器或范围将确保它们具有相同的映射。
正如我所说,提取已知字节并通过计算字段将其转换为字符串,日期,数字等是没有问题的。 将这些值重新转换为TBytes也是可能的。 问题是使这些额外的字段可编辑,同时保持数据集导航不变。
如果它有帮助:我们有类进行双向映射,将字段公开为已发布的属性。
答案取决于您使用的数据访问组件。 我正在使用Anydac,它支持fkInternalCalc字段,可以像手动编辑一样计算。
我认为计算字段按照定义是只读的,在客户端上计算值。 您想要的可能是可更新视图。 您可以使用计算字段定义视图 - 这些将在服务器上以SQL计算 - 以及更新触发器,也可以是插入触发器 - 以执行反向计算。 然后,从客户端,您可以像表一样透明地使用视图。
我有一个与ClientDataSet类似的问题,我已经在SQL-Stmt上使用虚拟文件解决了这个问题,所以我可以模拟数据库中的字段。
看我的问题
您可以使用TDatasetProvider.OnGetRecords(不记得这是否是事件的正确名称)并修改发送到Clientdataset的数据包。
当然,正如TOndrej所说,你必须在ApplyUpdates处理程序上处理它们。
在我们的数据库设计中,一些值是相对于另一列的百分比(在下面称为oMean
),而其他浮点值则存储为绝对值。 我们的客户后来想要所有字段的两个选项(rel。和abs。),所以我们想出了从TFloatField
派生的以下类。 它应该适用于所有TDataSet后代。
unit EditableCalcFloatField;
interface
uses
db, classes;
type
TEditableCalcFloatField = class(TFloatField)
public
oAbs, oRel, oMean: TField;
protected
function GetCanModify: Boolean; override;
procedure SetAsFloat(Value: Double); override;
end;
implementation
function TEditableCalcFloatField.GetCanModify: Boolean;
begin
Result := oMean.AsFloat <> 0;
if not Result then Exit;
Result := (oAbs <> nil) or (oRel <> nil);
end;
procedure TEditableCalcFloatField.SetAsFloat(Value: Double);
var
fMean : Double;
begin
inherited;
if DataSet.State in [dsEdit, dsInsert] then begin
fMean := oMean.AsFloat;
if fMean = 0 then Exit;
if oAbs <> nil then
oAbs.AsFloat := Value / 100 * fMean
else
oRel.AsFloat := Value / fMean * 100;
end;
end;
end.
要在没有包的情况下使用它,您必须在打开数据集之前在FormCreate
创建字段:
with TEditableCalcFloatField.Create(Self) do
begin
oAbs := sqlMerkmaleYourAbsoluteColumn;
DisplayLabel := sDisp;
oMean := sqlMerkmaleAssignedValue_Mean;
Calculated := True;
FieldName := 'R' + oAbs.FieldName;
DataSet := sqlMerkmale;
end;
当然,其内容可以在OnCalcFields
事件中设置,也可以由用户设置。
使用TQuery后代(MyQuery)和'Select *,0作为来自MyTable的TempField'
Procedure MyQueryAfterOpen(Dataset:TDataSet);
Begin
DataSet.FieldByName('TempField').ReadOnly := False;
End;
它现在是一个可编辑的临时字段
Woll2Woll的infopower组件(我刚刚测试了他们的TwwDBEdit)允许这样做。 所以我认为你在TDBEdit级别(或TFieldDataLink级别)阻止你。
在TwwDBEdit中究竟有什么不同,我不知道。 (而且我不确定许可协议是否允许我在这里发帖......)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.