报表开发框架

栏目:u9cloud知识作者:用友来源:用友发布:2024-08-20浏览:1

报表开发框架

报表开发流程

报表开发基本工艺路线

DataCommand

  1. 应用设计器设计DataComand模型
  2. 生成代码,添加取数逻辑。
  3. 调试

报表模板

  1. 导入DataCommand生成缺省报表模板。
  2. 应用报表设计器设计报表模板
  3. 报表模板发布

报表UI设计

  1. 报表方案管理设计(公共)
  2. 报表Form设计(结果Form绑定报表模板)
  3. 报表格式/数据处理策略。(应用报表元数据服务)
  4. 客户端展现。

DataCommand开发

说明

  1. 当报表数据查询逻辑复杂到无法用SQLOQL实现时需要自定义数据查询。
  2. ReportServer是报表主要服务器,UBF报表用自定义扩展类接管U9报表的所有数据读写功能。
  3. 数据查询扩展物理上与ReportServer运行于同一进程。
  4. 自定义的扩展类必须继承BaseReportDataCommand(基类提供接口的默认实现)。

用DataCommand实现复杂报表的设计步骤

        1.创建专用的工程,引用下列报表服务提供的组件

                                UFSoft.UBF.Report.Base.dll        

                            UFSoft.UBF.Report.Interface.dll 

        2.继承BaseDataCommand类创建业务逻辑实现类,确定业务逻辑中需要的查询参数。测试保证类能正确执行,特别是当参数无值是应按默认的参数值输出; 

        3.编译工程,并将动态库注册到报表设计器。

        4.在报表设计器中创建新报表,创建数据查询,将数据来源映射到业务逻辑实现类中(设计器提供特定的方法)。

        5.创建查询参数(查询参数的数量和名称应该在业务逻辑中已事先确定),将查询参数映射到报表参数。

        6.执行查询取得结果集合的Schema之后设计报表格式。

        7.发布动态库到报表服务器并注册。

        8.在设计器中调试报表,确定成功后发布报表。

继承BaseReportDataCommand实现报表复杂业务逻辑

BaseReportDataCommand基本编程模式

        BaseReportDataCommand用于支持服务器端业务逻辑编程模型,该类即实现了对报表数据逻辑的扩展又实现了向下的编程接口,任何复杂业务逻辑都必须继承该类。

  1. BaseReportDataCommand编程接口说明 

        

属性:

说明

 
 DefaultConnectString默认的数据库连接字符串 
QueryContext用于报表查询的上下文,运行环境中报表上下文将包含UBF系统上下文。 
Parameters报表查询参数集合 
Groups分组查询参数集合 
Orders排序参数集合  
 Select反映客户端栏目的变化
可覆盖方法:  
 IDataReader ExecuteDataReader()执行业务逻辑返回数据集
   
   

 

  1. BaseReportDataCommand生存周期

                

使用查询参数

 

 

    查询参数从基类的Parameters属性中获取,查询参数只用于业务逻辑中的数据过滤操作。类接口详细说明如下表:

    

类/接口

属性/方法

说明

 
IQueryParameter/QueryParameter查询参数描述  
 Name参数名称 
 Expression条件表达式:如果关联了报表参数:则按SQL条件语法返回当前条件项的条件表达式:如cDepCode =’01’ 
 DataType参数类型:字符、数值、日期、逻辑 
 Operator如果关联了报表参数:则返回界面输入比较方式,如>,=,<,<>,between等否则默认为等于 
 Values

返回参数值集合:如报表条件输入Between 10 to 20 则 Values{value[0]=10,value[2]

=20} ,如果输入值:in (10,20,30,40)则Values{value[0]=10,value[1]=20,value[2]=30}

 
 Value返回参数值集合的第一个元素,按参数类型转型。 
QueryParameterCollection   
 ToString():string将所有查询参数的条件表达式用 and 组织成不带Where子句的条件串  
 ToString(indexlist:int[]):string组织条件串,只用IndexList中枚举的查询参数 
 ToString(nameList:string[]):string组织条件串,只用nameList中枚举的查询参数 
    

使用分组参数

    

类/接口

属性/方法

说明

IGroupParameter/GroupParameter分组参数项 
 FieldExpression分组字段或表达式
GroupParameterCollection分组参数集合  
 ToString():string按SQL语法返回不带Group by关键字的分组子句

 

使用排序参数

 

    

类名

属性/方法

说明

IOrderParameter/OrderParameter排序参数项 
 FieldExpression排序字段或表达式
 OrderTrue  升序,false降序
OrderParameterCollection排序参数集合  
 ToString()按SQL语句返回不带Order by关键字的排序子句

使用栏目参数 

         

            

类名

属性/方法

说明

ISelectParameter/SelectParameter栏目参数项 
 FieldName栏目字段
   
SelectParameterCollection栏目参数集合 
  所有方法都继承自List类

 

使用上下文

    

类名

属性/方法

说明

QueryContext上下文参数,用于传递运行环境中的参数,或其它需要从客户段收集的参数,所有用于传递的对象都必须可序列化。 
 Add()增加上下文
 GetValue()取得上下文
 SetValue()设置上下文
 Contains()判断指定名称的上下文是否存在 
 Clear()清除所有的上下文
 Remove()删除特定的上下文
 ToBase64String() 
 FromBase64String() 

 

UFIDA.UBF.Report.App.Data 说明

DataCommand 功能

DataCommand 是利用报表服务传递过来的 报表参数,Selects,Groups ,Orders 等集合组织一个取数的逻辑。过程如下图所示:

 

3 步:给DataCommand设置数据源

4步:给DataCommand设置报表参数。

5步:给DataCommand设置上下文,包括Selects ,Groups,Orders等。

6步:调用DataCommand

7步:返回DataCommand的执行结果 IdataReader。

 

absDataCommand 实现的是上图中的第6步:执行具体的DataCommand执行取数逻辑。

 

该抽象类继承了报表引擎的 BaseReportDataCommand ,对该基类进行了简单封装,

所有DataCommand都必须继承此类。如下图:

 

在该类中提供了3中返回DataReader的方法:

A 重写 ExeDataReader 方法

对于简单报表可以重写该方法,不需要创建临时表,直接返回结果IdataReader

B 重写public virtual DataTable ExecuteDataTable() 方法。

 对于需要从 DataTable返回数据的报表可以重写 该方法。

 

对于A,B 两种方式都需要自己处理ShowMode=0时,返回空集的情况,一般可以给结果Oql加一个 where 0=1 的限定条件。

C 实现 GetOqlString()中的 ProcessData() 方法就可以了,该方式总是需要一个结果临时表,处理完后把最终的数据放入该临时表,这里代码生成时临时表名称是

ResultTempTable 。

 

DataCommand 主要属性,方法说明

 

1 ShowMode 参数说明:

ShowMode=0:表示返回空的临时表,在报表第一次展现或者报表业务处理逻辑出现错误时,返回空的临时表。

ShowMode=1 ,执行正常的报表逻辑,该常数在AbsReportDataCommand的已经做过处理。

 

 

2 EntityViewQuery :  viewQuery 

该对象主要用来执行Oql返回数据,创建临时表

注意: 利用该对象执行Oql时,需要使用一个数据库连接,该连接的状态有基类 BaseReportDataCommand来维护,在报表子类中不要处理,在整个报表业务逻辑处理要确保使用一个EntityViewQuery,不要使用 New EntityViewQuery 来创建。

 

3 在DataCommand中 报表服务给报表传过来几个集合:

关于查询参数,分组参数,排序参数,上下文的说明,参见:上面介绍

 Paramsters ,Selects ,Groups ,Orders ,QueryContext 

 

Paramsters :中包含了报表UI给DataComand的传过来的查询条件,其中包含两部分:

控制参数 ControlParams 

它主要是用来控制报表的格式,以及哪些条件,哪些栏目需要处理。一般不是作为报表的查询条件使用的(每个控制参数都需要特殊处理)

查询参数: 这是直接作为报表查询条件的,其中大部分条件可以直接使用,但是有小部分需要经过特殊处理后才能使用。(这是报表条件处理比较麻烦的一部分。)

 

 

GroupParameterCollection Groups

OrderParameterCollection Orders

SelectParameterCollection Select

Select:用户选择栏目

Groups :包含行分组,列分组

Orders:包含了哪些列需要进行排序,这个在DataCommand基类里已经做过处理。

 

4 List AllSelectFieldList

 

AllSelectFieldList : 包含了全部用户可以选择的列,一般情况Select 集合中只有用户选择的少量的列,而  AllSelectFieldList是全部列,应为DataCommand返回列总是固定的,所有只有Select集合中的列才需要取数,而其它列则取Null就可以了。

 

5 public override IDataReader ExecuteDataReader()

 

ReportService 调用DataCommand只需要返回一个dataReader ,该方法已经在基类里做了默认实现,在具体的DataCommand中就不需要实现了。在该方法中调用了报表取数的3中方式。

 

 A  该方法用于简单的报表,不需要创建临时表的情况

 public virtual IDataReader ExeDataReader()

  { 

        return null;

  } //end ExecuteDataReader

 

B //该方法用于返回DataTable的情况。

public virtual DataTable ExecuteDataTable()

{

  return null;

} //

C protected internal abstract string GetOqlString();

 

代码生成时生成了GetOqlString()方法

 

该方法需要每个DataCommand中都去实现具体的逻辑,要根据设计文档去写。

 

 

 

public virtual string GetResultOql(string tableName, string showMode)

该方法是构造一个最终结果的Oql:从结果临时表上取数。

ShowMode=0 时:返回空的结果临时表

Select * from TempTable where 0=1 

ShowMode=1 时返回正常的结果。

 

 

 

6 其它集合

FilterDefines FilterDefines

该集合是报表参数集合

FieldCollection FieldCollection

该集合是结果字段集合

 

List DefaultColumnList

该集合是DataCommand导入时,生成DataTable列的集合,如果该集合为空,则使用DataCommand返回的所有列。

 

以上3个集合是在代码生成时自动生成。并且在Extend文件中留有手工添加子项的方法块。

 

DataSource基类的说明

属性:

说明

 
 _util用于拼装结果Oql语句的工具类
 Selection Select  字段集合类
 ConditionsCondition  集合类
 Groups分组集合类
 Orders排序集合类
方法:  
 AddSelect(exp : string) : void为结果Oql添加select 子项
AddCondition(p:IQueryParameter) 为结果Oql添加条件 子项 
AddGroup(exp : string) : void为结果Oql添加分组 子项 
 AddOrder(exp : string, isAsc : bool)为结果Oql添加排序 子项
 GetOqlString() : String返回_util工具类拼装好的Oql
 SetCustomerJoinInfo(List )用于给数据源手工指定连接(该方法已经废弃)
 RemoveSelect(aliasName:string)删除栏目
 RemoveCondition(aliasName:string)删除条件
 RemoveGroup(aliasName:string)删除分组
 RemoveOrder(aliasName:string)删除排序

 

说明: 该类主要是为DataCommand提供拼装Oql的功能 ,简化其复杂度。所有数据源都必须继承该类.

AddSelect ,AddCondition,AddGroup,AddOrder方法都提供了多个重载.

 

工作原理:

实体别名Map: 主要是给实体定义别名影射,方便使用

 

aliasMap.Add("INVTotalCostLine" , "UFIDA::U9::InvTrans::MonthClose::INVTotalCostLine");

aliasMap.Add("ItemCategoryCross" , "UFIDA::U9::CBO::SCM::Item::ItemCategoryCross");

 

字段别名Map :定义字段别名影射

 

map.Add(INVTotalCostLine_SOB , "INVTotalCostLine.SOB");

map.Add(INVTotalCostLine_CostField , "INVTotalCostLine.CostField");

 

 

定义了实体Map,字段Map后,你可以使用 DataSourde提供的 

AddSelect ,AddCondition ,AddGroup ,AddHaving,AddOrder 等方法来提供Oql元素,最后调用 GetOqlString()来返回最终的Oql。

以上几个方法都提供了多种重载方法,请自己选择使用。

 

注意: 当你需要使用 Select Top 5 或者 Select distinct 的语句时 ,你需要先调用一下SetSelectKey(”select top 5 “),这样在返回Oql时会加上该语句。

 

SetCustomerJoinInfo(CustomerJoin) 该方法主要是用在 设置两个没有直接关联关系的两个实体建立连接的一种方式。

例如: 

           Ds.SetCustomerJoinInfo(new CustomerJoinInfo("INVTotalCostLine.INVTotal.ItemInfo.ItemID.ID", "ItemCategoryCross.Item", JoinType.LeftJoin));

调用该方法使 物料信息上的物料和物料交叉表通过物料的ID和物料交叉表的物料建立关联。你就可以使用物料交叉表的数据了。

 

 

说明:  该方法(SetCustomerJoinInfo)将要废弃 ,因为它始终要把指定的两个表进行连接,不管是否选取了 第二个实体的字段 ,这样会有效率问题。

 

现在推荐使用 如下方式 : 

在 DataSource 中重写 GetCustomJoinMap() 方法 

        public override IDictionary GetCustomJoinMap()

        {

            CustomerJoinInfo test1 = new CustomerJoinInfo("INVTotalCostLine.INVTotal.ItemInfo.ItemID.ID", "ItemCategoryCross.Item", JoinType.LeftJoin);

 

            IDictionary dic = new Dictionary();

 

            CustomerJoinInfo test2 = new CustomerJoinInfo("INVTotalCostLine.LotInfo.LotMaster.EntityID", "LotMaster.ID", JoinType.LeftJoin);

            //test2.ConditionString = MyDs.xxx + "=1";

           dic.Add("UFIDA::U9::CBO::SCM::Item::ItemCategoryCross", test1);

            dic.Add("UFIDA::U9::Lot::LotMaster", test2);

            return dic;

        }

 

这样在 只有在Oql中使用了 物料分类,批号中的属性时才会关联该表。

 

 

 

工具类的说明

方法:(静态方法)  
 String GetSql(string oql)将Oql翻译成Sql后返回
String GetSql(string oql,EntityViewQuery q)将Oql翻译成Sql后返回(用于带有临时表的语句 

 

方法:(静态方法) 
CreateTempTableByOql通过Oql创建临时表
AppendNonQueryForTempTable将新的Oql返回的数据附加到指定的临时表中
GetTempTableDataSet(tempTable,strOql,q)  通过Oql创建临时表,并将表中的数据作为DataSet返回。
GetTempTableDataSet(strOql,q)

通过Oql返回DataSet,q  用来读取临时表的数据

注意: q 必须和创建临时表的q  是同一个.

ExecuteDataReader(oql,

viewQuery: EntityViewQuery)

执行Oql从临时表中返回DataReader

ExecuteScalar(oql,

viewQuery: EntityViewQuery)

执行Oql返回结果集的第一行,第一列的值

 

 

方法:(静态方法) 
GetInString(List lnValues, bool inCludeSingleComma)返回由 List 子项构造的 In字符串
GetInString(DataSet ds,string columnName, bool inCludeSingleComma)返回由 DataSet中某列构造的 In字符串

 

UFIDA.UBF.Report.App.Data代码结构说明

关于DataCommand中的元素国际化问题:

 

定义一个资源管理类如下:

 

Public Class ResManager

{

        Public static Test

{

        Get

{

     Return “Test”;

}

}

}

Oql使用说明 

实体和数据库表的对应关系

实体属性有以下几种情况:

A 普通类型

 实体中的简单属性直接对应表中的字段(名称一致,类型一致)

 

B 通用实体

实体中的通用实体属性对应表中的两个字段: 类型名称_EntityID(long),属性类型名称_EntityType(varchar(100))

 

关于通用实体实体类型如何取:(对于通用实体只有EntityID,EntityType )

它会在本表中生成两个字段: 属性名_EntityID,属性名_EntityType

Oql:select  SOSourceEntityKey.EntityID , SOSourceEntityKey.EntityType 

from UFIDA::U9::SD::SaleOrder::SOShipline

 

Sql  select A.[SOSourceEntityKey_EntityID], A.[SOSourceEntityKey_EntityType] from  SD_SOShipline as A

 

C 属性类型 

实体中的一个属性类型对应表中的n个字段,格式:属性类型名称_属性类型下的属性名(类型一致)

(有几个属性就会在表中产生几个字段,如果该字段是国际化字段,该字段会产生在对应的国际化表中,

取这种字段时会关联国际化表)

 关于属性类型的取值方式(不能直接使用属性类型,只能使用它下面的字段)

例子:

Oql:

select  ShipmentPlanQtyTradeUOM.Amount ,ShipmentPlanQtyTradeUOM.UOM.Name 

from UFIDA::U9::SD::SaleOrder::SOShipline

 

Sql:

select A.[ShipmentPlanQtyTradeUOM_Amount], A2.[Name] 

from SD_SOShipline as A 

left join [Base_UOM] as A1 on (A.[ShipmentPlanQtyTradeUOM_UOM] = A1.[ID])

left join [Base_UOM_Trl] as A2 on (A2.SysMlFlag = 'zh-CN') and (A1.[ID] = A2.[ID])

 

这个ShipmentPlanQtyTradeUOM.UOM.Name通过本表中的ShipmentPlanQtyTradeUOM_UOM 再和UOM([Base_UOM])关联,

因为Name是国际化字段,所以要和[Base_UOM_Trl] 关联.

// ProvideSupplier 是属性类型

Oql:

select  ProvideSupplier.SupplierName  from UFIDA::U9::SD::SaleOrder::SOShipline

Sql:

select A1.[ProvideSupplier_SupplierName] 

from SD_SOShipline as A 

left join [SD_SOShipline_Trl] as A1 on (A1.SysMlFlag = 'zh-CN') and (A.[ID] = A1.[ID])

 

因为ProvideSupplier 是属性类型 所以ProvideSupplier.SupplierName 在本表(SD_SOShipline)中会有ProvideSupplier_SupplierName 又因为ProvideSupplier_SupplierName 是国际化字段,

所以要在SD_SOShipline 对应的国际化表中找。

 

 

D 实体类型

 

实体中的实体类型在本表中只保留一个Long型的字段(名称和属性名称一致)

当需要取该字段下的其他属性时(如:Name ) ,此时会产生和该实体的关联来取该实体的字段

报表开发框架

报表开发流程报表开发基本工艺路线DataCommand应用设计器设计DataComand模型生成代码,添加取数逻辑。调试报表模板导入DataCommand生成缺省...
点击下载文档
标签: # U9C
分享:
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息