• FormDataSource初探(一)


    概述
    作为数据存储和展示的中间对象,FormDataSource在Form中的地位举足轻重,可以说理解了FormDataSource中的方法和事件,也就掌握了Form大部分的内容.本文试图解释清楚FormDataSource的主要方法和属性.
    由于Dynamics Axapta的帮助文档还在完善中,本文的部分解释来自于自己的测试,也许不能全面地反映设计者的意图.有纰漏的地方,还望看到本文的同行多多指教.
    数据访问
    由于Axapta的平台核心代码是没有公开的,FormDataSource方法的代码是看不到也跟踪不到的,所以没办法知道它内部的处理逻辑,不过还是可以用现有的工具窥探其原理,对于数据访问层,我们可以用Axapta提供的SQL跟踪工具,通过查看它执行的SQL语句来推测,如何设置SQL跟踪,这里就不赘述了.
    这里以一个简单的示例测试来说明,创建一个窗体CustTableTest,设定其数据源为CustTable,并在Design中创建一个Grid,将CustTable的AccoutNum和Name字段拖到上面.
    点击数据源的属性,可以看到如下几个与数据抓取有关的属性:
    1.AutoQuery
    解释:
    FormDataSource这个类中有个方法是Query,原型如下:
    public final Query query( [Query _value] )
    Axapta给FormDataSource提供了两种访问数据库的方式,一种是通过Query,另一种是通过SQL语句,当然这两种方式都是通过FormDataSource的ExcuteQuery方法去执行的,如果FormDataSource的Query方法返回的对象被实例化了,则会调用QueryRun实现查询,如果没有则会直接采用与数据源相关的语句实现查询(这个没有相关的文档介绍,可以通过跟踪生成的SQL语句来查看.
    如果设定AutoQuery的属性为Yes,则窗体CustTableTest运行的SQL语句如下(为了节约篇幅,将客户表里的字段用*表示):
    User ID: Admin
    Time: 
    15:06:12 2006-12-29
    Version: Microsoft Business Solutions
    -Axapta 3.0 (Build number 1951.4060)
    Database: Microsoft SQL Server
    SQL statement: 
    SELECT * FROM CUSTTABLE A WHERE (DATAAREAID=?) ORDER BY A.DATAAREAID,A.ACCOUNTNUM OPTION(FAST 1[ID=12, Reused=Yes]
    Call stack:
    \Classes\QueryRun\
    next
    \Classes\FormDataSource\executeQuery
    可以看出,Axapta是通过QueryRun这个对象来查询数据的.
    如果把AutoQuery设为No,则执行的语句如下:
    User ID: Admin
    Time: 
    15:08:58 2006-12-29
    Version: Microsoft Business Solutions
    -Axapta 3.0 (Build number 1951.4060)
    Database: Microsoft SQL Server
    SQL statement: 
    SELECT * FROM CUSTTABLE A WHERE (DATAAREAID=?) ORDER BY A.DATAAREAID,A.ACCOUNTNUM OPTION(FAST 1[ID=15, Reused=No]
    Call stack:
    \Classes\FormDataSource\executeQuery
    可以看出,Axapta并没有通过QueryRun对象来实现查询,而直接通过excuteQuery来实现了数据的查询.
    当然Axapta的BP里说这个AutoQuery必须设为Yes,不过在了解了其原理之后,大可不必受限与此,当初设计者暴露了这个开关,还是有他的用意的.在实现较为复杂的查询时,用Query对象结构来构造查询是有些不方便的.
    这里有一个问题是,采用Query的时候可以很容易地猜测到excuteQuery这个方法用Query对象构造了一个QueryRun出来,然后执行查询,我们如果不通过Query来构造查询,如何直接用select from等关键字来构造查询那?excuteQuery怎么知道应该执行什么SQL语句?看不到excuteQuery的源代码只能猜测啦.
    将数据源的AutoQuery属性设为No,在数据源CustTable的init方法中添加如下代码:
    public void init()
    {
        super();
        
    select accountNum,Name from custTable
        
    where custTable.AccountNum == '4000';
    }
    打开窗体,这时查看执行的SQL语句:
    User ID: Admin
    Time: 
    15:22:03 2006-12-29
    Version: Microsoft Business Solutions
    -Axapta 3.0 (Build number 1951.4060)
    Database: Microsoft SQL Server
    SQL statement: 
    SELECT A.ACCOUNTNUM,A.NAME,A.RECID FROM CUSTTABLE A(INDEX(I_077ACCOUNTIDX))  WHERE ((DATAAREAID=?) AND (ACCOUNTNUM=?)) ORDER BY A.DATAAREAID,A.ACCOUNTNUM OPTION(FAST 1[ID=3, Reused=No]
    Call stack:
    \Forms\CustTableTest\Data Sources\CustTable\Methods\init 
    - line 4

    User ID: Admin
    Time: 
    15:22:03 2006-12-29
    Version: Microsoft Business Solutions
    -Axapta 3.0 (Build number 1951.4060)
    Database: Microsoft SQL Server
    SQL statement: 
    SELECT A.ACCOUNTNUM,A.NAME,A.RECID FROM CUSTTABLE A(INDEX(I_077ACCOUNTIDX))  WHERE ((DATAAREAID=?) AND (ACCOUNTNUM=?)) ORDER BY A.DATAAREAID,A.ACCOUNTNUM OPTION(FAST 1[ID=4, Reused=No]
    Call stack:
    \Classes\FormDataSource\executeQuery
    我们可以看到第二段SQL脚本,在excuteQuery中执行的SQL语句实际上就是在init中执行的那段.
    由此我们可以猜测,只要在数据源的init方法中(或者其他什么地方,只要在excuteQuery之前就可以了)定义好一个SQL语句(可以包含其他任意表和任意复杂的查询),当然前提是这个SQL语句中必须包含与当前数据源名称相同的表变量(比如本例中的custTable),在excuteQuery执行的时候就会执行这条SQL语句,至于它是的逻辑,俺想了半天都没想通,按照文档的解释,custTable相当于FormDataSource.Cursor, DataSource引用的物理表的当前记录,为什么这样就可以让excuteQuery执行在init定义的SQL语句,就不晓得了.
    这里还有个问题,当然不希望同样的SQL语句执行两次,如何使init方法定义一个在excuteQuery执行的查询而在init方法中并不执行查询动作?这或许就是X++里为什么要出现nofetch这个关键字的原因了,原来看文档的时候,总是想这么个稀奇古怪的关键字做啥子用啊?既然当前不执行查询,那就什么时候要执行查询的时候再select不就OK了?何必曲线救国?在这里nofetch就有用武之地了,把前面在init定义的方法修改如下:
    public void init()
    {
        super();
        select nofetch accountNum,Name from custTable
        where custTable.AccountNum 
    == '4000';
    }
    这样,再看执行的SQL脚本时,就只剩下在excuteQuery执行一次了.在init方法中定义要执行的SQL脚本,然后在excuteQuery方法中执行,这或许就是nofetch的本意?
    应用场景:
    绝大多数情况下应该按照BP的要求,将这个属性设为Yes,但如果要构造的查询很复杂,涉及到很多表,用Query难以构造时,可以考虑将其设为No,然后在init方法中用select等X++关键字构造查询.
    2.AutoSearch
    解释:
    这个属性是用来表示在第一次加载窗体的时候要不要执行FormDataSource的excuteQuery方法,如果设为Yes,则在FormRun的Run方法中会调用FormDataSource的excuteQuery方法,否则不调用,由于FormDataSource的数据通过excuteQuery方法取得,不调用该方法意味着窗体不会加载任何数据.
    应用场景:
    大多数情况下应该按照BP的要求,将该属性设为Yes,记得原来写Asp.Net程序的时候,为了加快页面的加载数据,第一次加载页面的时候并不加载数据,在用户选择条件,点击按钮后再加载,这样加载的数据相对少一些,速度也会快一些,如果有这样的需求的话,可以考虑将该属性设为No.
    3.OnlyFetchActive
    解释:

    主要是理解Acitve,什么的是Active的?就是要在Form上显示的字段.这个属性的意思是,是否只抓取要在Form上显示的数据,不过这个好处只有在AutoQuery设为Yes的时候才会享受到,自己构造Query或者通过SQL查询出来,是不能享受这个待遇的,因为Axapta咋知道你在瞎折腾啥?
    另外把这个属性设为Yes,为了保持数据的一致性,Axapt是不允许删除其中的记录的,如果强行删除它会给你个error see see.
    应用场景:
    这个属性是为Lookup窗体量身打造的,由于只需要从数据库中查询要显示的字段,速度无疑会增加不少.如果是普通窗体建议在没有特别的理由,就不要动这个属性,让它保持为默认值No吧.
  • 相关阅读:
    性能优化之
    gruntjs开发实例
    从数组里随机获取N项
    调试工具-fiddler:本地资源替换线上调试
    HTML5-canvas实例:2D折线数据图与2D扇形图
    移动前端兼容性笔记
    Less开发指南(三)- 代码文件跟踪调试
    像纸质笔记本一样给div,textarea添加行的分割线
    基于视图的增删改查操作(颠覆传统思维吧)
    恶劣的百度推广人员
  • 原文地址:https://www.cnblogs.com/Farseer1215/p/607123.html
Copyright © 2020-2023  润新知