本文通过几个列子解释FetchMode的使用,最后解释reportRun.Send()方法的第二个参数level的来源。
FetchMode
报表的Query的除最上层的DataSource以外所有的DataSource都有一个FetchMode属性,该属性有两个值: “1:n” 和 “1:1”.
FetchMode的设置不会影响到查询语句,也就是说,如果你构造了一个Query实现类型于: select SalesLine
Join salesTable where salesLine.salesId == salesTable.salesId;
那么你将FetchMode设置为”1:n” 或者”1:1”, Query所等价的语句,始终是如上的语句。
FetchMode的作用有两点,一是可以影响DataSource的连接方式(影响查询语句),二是可以影响fetch方法在调用send方法是实参的值。下面我们做一个演示:
演示1:FetchMode对查询语句的影响
图1-1
如图1-1,该Query的结构是一个SalesLine连接两个表SalesTable和CustTable, 但这两个子表是在同一个level的(表之间的Relation必须根据实际情况建立)。
如果你将SalesTable_1和CustTable_1的FetchMode参数设置为”1:n”, 实际的查询语句并不是:
Select SalesLine
Join SalesTable where SalesTable.SalesId = salesLine.salesId
Join CustTable where CustTable.AccountNum == SalesLine.CustAccount;
而是:
先查询:select salesLine;
再查询:select SalesTable where SalesTable.SalesId == SalesLine.SalesId;
最后: select CustTable where CustTable.AccountNum == SalesLine.CustAccount;
当你将FetchMode设置为 “1:1”时,才可以得到这样的查询语句:
Select SalesLine
Join SalesTable where SalesTable.SalesId = salesLine.salesId
Join CustTable where CustTable.AccountNum == SalesLine.CustAccount;
如果你将Query的结构设置成为如图1-2:
图1-2
SalesTable和CustTable的FetchMode属性都为”1:n”, 实际的查询语句将同样是:
Select SalesLine
Join SalesTable where SalesTable.SalesId = salesLine.salesId
Join CustTable where CustTable.AccountNum == SalesLine.CustAccount;
演示二:对send方法实参的影响
同样以图1-2的结果来做讲解,如果将SalesTable和CustTable的FetchMode属性都设置为”1:1”, 那么在fetch方法中,运行的过程类似于这样:
While (this.queryRun().next())
{
custTable = this.queryRun().get(tablenum(CustTable));
this.send(custTable,3,false);//第二个参数将在后面解释
//第三个参数表示是否调用对应的excutesection方法运行,false表示不调用
SalesTable = this.queryRun().get(tablenum(SalesTable));
This.send(salesTable,2,false);
SalesLine = this.queryRun().get(tablenum(SalesLine));
This.send(salesLine,1,true);
}
如果将SalesTable和CustTable的FetchMode属性都设置为”1:n”, 那么在fetch方法中,运行的过程类似于这样:
While (this.queryRun().next())
{
SalesLine = this.queryRun().get(tablenum(SalesLine));
This.send(salesLine,1,true);
SalesTable = this.queryRun().get(tablenum(SalesTable));
This.send(salesTable,2,true);
custTable = this.queryRun().get(tablenum(CustTable));
this.send(custTable,3,true);
}
到目前为止,我所展示的代码只是为了告诉你,FetchMode究竟如何影响了fetch方法调用send方法,但系统实际上做到事前不止这些,下面的例子将向你演示系统究竟是如何做到:
图1-3
图1-3所示的report中,如果将SalesLine的FetchMode设置为”1:n”,在fetch方法是这样执行的:
Boolean Fetch()
{
Boolean ret = true;
QueryRun qr;
SalesTable salesTable;
SalesLine salesLine;
;
Qr = new QueryRun(element);
While(qr.next())
{
If (qr.changed(tablenum(SalesTable)))
{
salesTable = qr.get(tablenum(SalesTable));
this.send(salesTable,1,true);
}
If (qr.changed(tablenum(SalesLine)))
{
salesLine = qr.get(tablenum(SalesLine));
this.send(salesLine,2,true);
}
}
Return ret;
}
如果将SalesLine的FetchMode设置为”1:1”,在fetch方法是这样执行的:
Boolean Fetch()
{
Boolean ret = true;
QueryRun qr;
SalesTable salesTable;
SalesLine salesLine;
;
Qr = new QueryRun(element);
While(qr.next())
{
If (qr.changed(tablenum(SalesTable)))
{
salesTable = qr.get(tablenum(SalesTable));
salesLine = qr.get(tablenum(SalesLine));
this.send(salesLine,2,false);
this.send(salesTable,1,true);
}
Else if (qr.changed(tablenum(SalesLine)))
{
salesLine = qr.get(tablenum(SalesLine));
this.send(salesLine,2,true);
}
}
Return ret;
}
系统实际的代码不是这样,但他所实现的结果是相同的。看起来很奇怪,但是系统就是类似与这样做的,所以在你使用FetchMode属性时,考虑一下fetch取数据的方式是否能够满足你的需要。
FetchMode小结:
在你确定子数据源和父数据源的关联是1:1的时候时,根据你的需要决定是否将设置FetchMode为1:1。
1. 如果你不打算让子数据源来激活某一个BODY或Section来运行,那么你完全可以将FetchMode设置为1:1,否则请设置为1:n
2. 如果你想让子数据源和父数据源在同一个BODY里显示,那么你也完全可以将FetchMode设置为1:1
3. 如果子数据源和父数据源的关系不是1:1,请你不要将FetchMode设置为1:1,除非那就是你想要的结果。
send方法的参数level
当将一个表作为DataSource放入Query中时,每个DataSource都会有一个level,代表该DataSource在整个query中的层次。这个level值是从根DataSource向下,每增加一个层次,就将level值增加1.
如图1-1, SalesLine 的Level值为1, SalesTable的level值是2, CustTable的level值是2.
如图1-2, Salesline 的level值是1, SalesTable的level值是2, CustTable的level值是3.
系统在获取到一个记录时,会根据其对应的DataSource的层次也即level来设置send方法的第二个参数。
但是,这个参数究竟起什么作用,我不是很明白,根据目前的测试,并没有发现它能够引起本质上的改变。如果谁研究出来了,希望能告诉我。