鉴于网络上对Dynamics NAV所使用的C/AL语言资源较少,于是乎整理了C/AL中所常用的函数用法以供大家学习讨论。
首先是在C/AL Symbol Menu中,Rec-->Miscellaneous下的函数用法,从FINDFIRST到CALCSUM的用法。接下来会更新余下用法。
FINDFIRST:
用于在表中查找符合当前筛选条件的第一条记录。它会根据当前的SETCURRENTKEY和SETFILTER条件从头开始查找第一条匹配的记录
语法:
IF Rec.FINDFIRST THEN BEGIN
//第一条操作记录
END;-----------(Rec:一个已定义的Record变量,如Customer,Item......)
------------------(FINDFIRST:返回值为Boolean,找的符合条件返回True,否则False
例如:查找第一位活跃用户---------------------------------------------------------------------------------------
Customer.SETFILTER("Blocked", '<>%1', Customer."Blocked"::All);
IF Customer.FINDFIRST THEN BEGIN
MESSAGE('第一个活跃用户是:%1', Customer.Name);
END ELSE BEGIN
MESSAGE('没有找到活跃用户');
END;
--------------------------------------------------------------------------------------------------------------
FINDLAST:
与FINDIFRST相反
FINDSET:
用于遍历多个记录的函数,它会在当前过滤的条件和排序键下,返回一个记录集合,可以使用REPEAT...UNTIL循环来逐条赌球这个集合中的每条记录
FINDSET(ForUpdate,LockTable)参数解释:
ForUpdate(Boolean):是否打算修改记录( 设置为True会申请写锁)
LockTable(Boolean):是否锁定整个记录集
通常两个设置为false可以提高读取性能
语法:
IF Rec.FINDSET THEN BEGIN
REPEAT
//对每条记录进行处理
UNTIL Rec.NEXT = 0;
END;
例如:遍历所有未完成订单---------------------------------------------------------------------------------------
SalesHeader.SETFILTER("Document Type", '1%', SalesHeader."Document Type" :: Order);
SalesHeader.SETFILTER(Status, '<>%1' , SalesHeader.Status::Released);
IF SalesHeader.FINDSET THEN BEGIN
REPEAT
MESSAGE('订单号:%1,客户:%2', SalesHeader. "No.", SalesHeader."Sell-to Customer Name")
UNTIL SalesHeader.NEXT = 0;
END;
--------------------------------------------------------------------------------------------------------------
GET:
用于通过主键值从数据库中查找并读取一条记录(找到记录:系统将其载入Record变量。找不到记录:系统直接报错(不是返回Fales而是抛出运行时错误)
可以使用ISRECORD函数或者IF GET THEN 包装成自定义函数来处理GET不存在的情况
语法:
Rec.GET(Value1 [, Value2,..]);
例如:根据主键查找客户------------------------------------------------------------------------------------------
Customer.GET('10000');
MESSAGE('客户名称:%1' , Customer.Name);
//如果编号为‘10000’客户不存在,系统将报错:‘Record does not exit’
-------------------------------------------------------------------------------------------------------------------
//假如表中(如Sales Line)有两个主键字段"Document Type"和“Document No."
SalesLine.GET(SalesLine."Document Type"::Order, 'so000123');
-------------------------------------------------------------------------------------------------------------------
FIND:
用于定位记录指针的方法,可以灵活地按指定方向查找记录
它不返回一组记录,而是返回当前过滤条件下的一条记录(取决于参数),并将Record变量定位到该记录
语法:
IF Rec.FIND(Direction) THEN BEGIN
//找到了,Record指针已定位
END;
参数:
'=' 查找当前指针位置(用于已知当前记录)
'-' 查找第一条记录(相当于FINDFIRST)
'+' 查找最后一条记录(相当于FINDLAST)
'>' 查找大于当前记录的下一条记录
'<' 查找小于当前记录的上一条记录
例如:查找大于当前记录的下一条--------------------------------------------------------------------------------
IF SalesHeader.FIND('>') THEN BEGIN
MESSAGE('下一笔顶带你是:%1' , SalesHeader."No.");
END;
-------------------------------------------------------------------------------------------------------------------NEXT:
是Record类型的方法,用于将当前记录指针移动到下一条记录,并返回是否成功
返回值有:
>0:成功移动到下一条记录
0:没有更多记录(到达结尾)
<0:表示错误
语法:
Record.NEXT;
---------------------------(or)
REPEAT
//处理当前记录
UNTIL Record.NEXT=0;
例如:与FINDSET配合遍历记录----------------------------------------------------------------------------------
IF Customer . FINDSET THEN BEGIN
REPEAT
MESSAGE('客户:1%', Customer.Name);
UNTIL Customer.NEXT = 0;
END;
-------------------------------------------------------------------------------------------------------------------
RESET:
是Record数据类型方法,用于将指定的Record变量恢复到默认状态
1.清除所有的筛选器(SETRANGE , SETFILTER)
2.清楚排列键(SETCURRENTKEY)
3.关闭SETAUTOCALCFIELDS设置
4.保留记录变量的数据源(表)
语法:
Rec.RESET
例如:配合多次筛选使用------------------------------------------------------------------------------------------
Item.SETFILTER("Inventory", '>0');
IF Item.FINDFIRST THEN
MESSAGE('有库存的第一个物料是:%1', Item."No.");
Item.RESET;
Item.SETFILTER("Inventory", '<=0');
IF Item.FINDFIRST THEN
MESSAGE('无库存的第一个物料是:%1' , Item."NO.");
-------------------------------------------------------------------------------------------------------------------
SETCURRENTKEY:
用于设置当前的Record变量操作时使用的索引键(排列顺序),影响后续FIND*, SETFILTER, FINDSET, CALCSMUS等操作的性能和结果,它决定了数据的读取顺序,是否使用已有的数据库索引,是否能进行某些聚合计算(CALCSUMS)
语法:
Rec.SETCURRENTKEY(Field1 [,Field2,...]);
//参数为表中的索引字段名称,参数顺序必须是表定义中某个已存在的索引顺序(主键或辅助键)
例如:在Item表中按“物料类别+编号”排序读取----------------------------------------------------------------
Item.SETCURRENTKEY("Item Category Code", "NO.");
Item.SETFILTER("Item Category Code", 'FINISHED');
IF Item.FINDSET THEN BEGIN
REPEAT
MESSAGE('物料:%1,类别:%2' , Item."No." , Item."Item Category Code");
UNTIL Item.NEXT = 0;
END;
-------------------------------------------------------------------------------------------------------------------
ASCENDING:
设置排列方向为升序
语法:
Rec.ASCENDING(TRUE); //升序
Rec.ASCENDING(FALSE); //降序
例如:按客户编号升序排列---------------------------------------------------------------------------------------
Cusomer.SETCURRENTKEY("No.");
Customer.ASCENDING(TRUE);
IF Customer.FIND('-') THEN BEGIN
REPEAT
MESSAGE('客户编码:%1' , Customer."No.");
UNTIL Customer.NEXT = 0;
END;
-------------------------------------------------------------------------------------------------------------------
LOCKTABLE:
用于控制并发访问和锁定数据库表,对当前Recoed变量所表示的表加排他锁,防止其他用户或会话同时读取或修改这张表的数据。常用于事务的完整性控制,确定读写期间数据不被其他用户修改,避免并发冲突
语法:
Rec.LOCKTABLE([Wait[);
//Wait(可选,Boolean):是否等待解锁。TRUE:如果表被锁,等待。FALSE:如果表被锁,报错
例如:尝试锁定,不等待------------------------------------------------------------------------------------------
IF NOT Customer.LOCKTABLE(FALSE) THEN BEGIN
ERROR('客户表正被其他用户使用,无法锁定');
END;
-------------------------------------------------------------------------------------------------------------------
CALCFIELDS:
用于计算FlowField字段的值。
语法:
Rec.CALCFIELDS(Field1 [ , Field2 , ])
//参数必须是一个或多个FlowField,必须对每一个FlowField显示调用CALCFIEDER才能使用它的值
例如:读取物料的库存数量(Inventory 是 FlowField)------------------------------------------------------------
Item.GET('1000');
Item.CALCFIELDS("Inventory");
MESSAGE('物料:%1的库存数量是:%2' , Item."No ." , Item."Inventory");
-------------------------------------------------------------------------------------------------------------------
CALCSUMS:
用于对一个Record集合中指定的SumIndexFields(可汇总字段)做求和操作。它会根据设置的键,过滤去等条件,计算出字段的合计值,结果存储在当前记录变量中。
语法:
Rec.SETCURRENTKEY(IndexField); //设置索引(必须)
Rec.SETFILTER(FilterField , Filter); //设置条件(可选)
Rec.CALCSUMS(SumField1 [,SumField2,...]) //聚合字段
例如:求物料库存总和--------------------------------------------------------------------------------------------
Item.SETCURRENTKEY("Item Category Code");
Item.SETRANGE("Item Category Code" , 'FINISHED');
Item.CALCSUMS("Inventory");
MESSAGE('FINISHED 类别的库存总和是:%1' , Item.Inventory);
-------------------------------------------------------------------------------------------------------------------