查询开发框架
概述
BE查询方式的执行过程
- 根据BE实体的元数据来生成默认的CaseModel
- 用户在查询方案画面中,调整条件、栏目、排序
- 使用BEQueryStrategyImpl将CaseModel转化成UIView
- 调用平台的UIView机制生成并执行OQL,将返回的结果放入UIView中,然后绑定到UIGrid 上
DTO查询方式的执行过程
- 根据所设计的DTO的元数据来生成默认的CaseModel
- 用户在查询方案画面中,调整条件、栏目、排序
- 使用DTOQueryStrategyImpl获得CaseModel转化成QryCommonParaObj,并传入到查询BP中执行
- 查询BP根据QryCommonParaObj来实现具体的查询逻辑,并将结果返回并填充UIView中,然后绑定到UIGrid 上
BE方式与DTO方式的比较
| BE方式 | DTO方式 |
复杂度 | 逻辑简单 | 逻辑复杂(多次查询、临时表) |
CaseModel的生成方式 | 根据BE元数据来生成CaseModel | 根据DTO元数据来生成CaseModel |
OQL | 平台负责生成OQL | 自己拼写OQL |
实体间的关系 | 一个主实体,多个子实体,能使用A.B.C的oql语法 | 多个实体,之间为弱引用关系,不能通过A.B.C的oql语句来查询,需要自己拼接oql语句。或通过临时表来做二次查询。或使用DataTable处理 |
BE方式查询的设计与开发
1.设计期—UI端
与列表UI开发的不同点:选择“查询模板”(没有删除和新增按钮),根据WebPart关联方式来选择如何拖UIView中的字段(参见WebPart关联部分)
命名规范:与列表开发类似,但要将其中的BList变成BQry,一定要注意这点
UI端代码—Ation部分
//数据加载的扩展
private void this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
BEQueryStrategyImpl beQryStrategyImpl = new BEQueryStrategyImpl(this.CurrentState, EntityFullName, QryModelID, this.CurrentModel.QCDocLine, UIGrid,1);
beQryStrategyImpl.Adjust();
this.MainView.CurrentFilter.OPath = QryService.GetDefaultOpath((UFSoft.UBF.UI.FormProcess.BaseWebForm)(this.CurrentPart));
//如果本Webpart是消费者,则需要处理传入的Webpart关联参数,可以参见下面的方式(这部分要根据自己的情况编写):
if (this.MainView.CurrentFilter.Parameters != null && this.MainView.CurrentFilter.Parameters.Count > 0)
{
string sOPath = this.MainView.CurrentFilter.OriginalOPath;
foreach (IUIParameter paradata in this.MainView.CurrentFilter.Parameters)
{
if(paradata.DataValue!=null)
sOPath = sOPath.Replace(paradata.Name, paradata.DataValue.ToString());
}
this.MainView.CurrentFilter.OPath += " and " + sOPath;//将“查询方案中的条件”与“Webpart关联的传入参数”合到一起
}
//处理排序
this.CurrentModel.QCDocLine.CurrentFilter.OrderBy = QryService.GetOrderByOpath((BaseWebForm)(this.CurrentPart));
//增加代码,调整UIView
this.CurrentModel.QCDocLine.Clear();
this.NavigateAction.FirstPage(null);
if (this.MainView.Records.Count == 0)
{
this.CurrentPart.ShowWindowStatus(PDResource.GetNoRecordSucessInfo());
}
else
{
this.CurrentPart.ShowWindowStatus(PDResource.GetFindSucessInfo());
}
}
public void InitCaseModel()
{
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
BEQueryStrategyImpl beQryStrategyImpl = new BEQueryStrategyImpl(this.CurrentState, EntityFullName, QryModelID, this.CurrentModel.QCDocLine, UIGrid,1);
//增加代码,调整BE元数据加载方式
CaseModel caseModel = beQryStrategyImpl.GetQryModel();
//增加代码,调整CaseModel
QryService.SetCaseModelToSession((BaseWebForm)(this.CurrentPart), caseModel);
}
UI端代码—WebPart部分
public void After UpdatePanelUpdateMode.Always;
//this.IsProviding = true;//如果在Webpart关联中,本WebPart是提供者,则需要加入这段话
//绑定BE方式的分页事件
GridNavigateAction.GetInstance().AttachMakePageEvent(this.Action, this.DataGrid1);
}
public void BeforeUIModelBinding()
{
if (QryService.IsCallInitCaseModel(this.DataGrid1))
{
this.Action.InitCaseModel();
}
if (QryService.IsCallAdjust(this.DataGrid1))
{
this.Action.QueryAdjust();
}
else
{
QryService.SetGridWidthToCase(this.CurrentState, FormID, this.DataGrid1);
}
}
public void AfterUIModelBinding()
{
QryService.BindEnum("DDLCase", this, this.Action.QryModelID);
//加入调整UIGrid的代码
}
UI端代码—BE正拖模型方式下的Action部分
以往做列表时,都是倒拖,即在UIView中拖子,从子找到主。
还有一种是正拖方式,即从主找到子,即生成CaseModel时,要加载集合特性的子。这需要在InitCaseModel添加代码,如下颜色标记:
public void InitCaseModel()
{
QryService.ClearSession((BaseWebForm)(this.CurrentPart));
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
BEQueryStrategyImpl beQryStrategyImpl = new BEQueryStrategyImpl(this.CurrentState, EntityFullName, QryModelID, this.MainView, UIGrid, 2);
beQryStrategyImpl.IsLoadCollectionAttrs = true;
…
…
采用正拖模型,转成oql语句执行后,得到的结果是一个主对应多个子的形式,如下:
ID(主ID) | 主表中的字段 | 子ID | 子表中的字段 | 。。。 |
1 | … | 3001 | … | |
1 | … | 3002 | … | |
2 | … | 4001 | … | |
2 | … | 5001 | … |
如果是这种样式的记录,在添充到UIView.Recors中时,平台对于重复ID的记录,只取第一条记录。如下:
ID(主ID) | 主表中的字段 | 子ID | 子表中的字段 | 。。。 |
1 | … | 3001 | … | |
2 | … | 4001 | … |
因此,如果想要展现第一种样式的数据,必须对ID字段做一些处理,即生成一个顺序号来代替主ID字段。这需要在QueryAdjust中改变UIView中UIField,代码如下:
public void QueryAdjust()
{
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
BEQueryStrategyImpl beQryStrategyImpl = new BEQueryStrategyImpl(this.CurrentState, EntityFullName, QryModelID, this.CurrentModel.PayrollSupply, UIGrid, 2);
beQryStrategyImpl.Adjust();
this.CurrentModel.PayrollSupply.CurrentFilter.OPath = QryService.GetDefaultOpath((BaseWebForm)(this.CurrentPart));
this.CurrentModel.PayrollSupply.CurrentFilter.OrderBy = QryService.GetOrderByOpath((BaseWebForm)(this.CurrentPart));
//将原来的“ID”变成“顺序号row_number”,注意大小写(oql中的关键字应该全是小写的)
IUIField uiField = this.MainView.Fields["ID"];
uiField.AttributeName = "row_number() over(order by ID asc)";
if (this.MainView.Fields["PID"] == null)
{
//新增一个PID来存放“主表ID”-----------------------↓ID的别名------------↓字段类型-----------------------↓原字段名
IUIField fieldParentID = new UIField(this.MainView, "PID", Type.GetType("System.Int64"), true, "0", "PID", "ID", false, true, false, "", false);
this.MainView.Fields.Add(fieldParentID);
}
this.MainView.BuildFieldIndexes();//调整UIView中UIField结构后,必须重建其字段索引
this.CurrentModel.Views["PayrollSupply"].Clear();
this.NavigateAction.FirstPage(null);
if (this.MainView.Records.Count == 0)
{
this.CurrentPart.ShowWindowStatus(PDResource.GetNoRecordSucessInfo());
}
else
{
this.CurrentPart.ShowWindowStatus(PDResource.GetFindSucessInfo());
}
}
该段代码的CC路径:/View/U9UICode/U9.VOB.PD.HR/Pay/Code/PayrollSupplyUI/
DTO方式查询的设计与开发
DTO方式查询分为五个环节:设计期(UI端、DTO、BP端),代码(UI、BP)
设计期—UI端
与列表UI开发的不同点:选择“查询模板”(没有删除和新增按钮),根据WebPart关联方式来选择如何拖UIView中的字段(参见WebPart关联文档)
命名规范:与列表开发类似,但要将其中的BList变成BQry,一定要注意这点
设计期—DTO设计
在本方案中用DTO来定义查询的待选项集合,并且该DTO必须作为查询BP的返回值(IList)。
数据类型限制
一般来说,DTO中的每一个属性就对应一个待选项,作为约定,其数据类型必须是原生类型、强类型的实体Key类型、枚举类型。下图的System下的前面若干项是可选的。xml、对象类型、空类型、实体key类型是不可选的。
所谓的强类型实体key的定义应如下图:
先选上一个实体,然后在实体key选项框中打上勾。
作为约定,强类型的实体Key属性不作为待选项,但可以作为条件及排序待选项,并且不能展开下级。
查询DTO设计中的注意事项:
- 必须有ID字段
- 如果返回的记录中ID列有重复, Grid会中会只显示一行记录。对于这种情况,可以将row_number()做为ID列。(可参考《查询列表常见问题及解决办法》中的“正拖模型”部分)
- 属性的名称用于拼OQL时Seclect子句的别名,同时也会对应UIView的UIField名称及Grid的列名。(理解这点很重要!!!!)
- 选择合理的字段类型
- 根据业务需求,设计合理的查询属性(条件待选、栏目待选、排序待选、默认栏目)
- 每次调整DTO后,要注意重新构造并执行相应的sql脚本(发布元数据)
设计期—BP设计
入口参数
所有查询BP的入口参数的类型都必须是查询公共部份提供的DTO(查询BP通用入参DTO)。
此DTO中包含有已选栏目、过滤、排序等信息,BP开发人员可根据这些参数,构造符合业务的OQL语句。定义方式如下图:
返回值
所有查询BP都必须以描述待选项集合的DTO集合为BP的返回值
应用版型
为了让查询BP在构造时产生骨架代码,在BP设计器中要选中该BP,点右键,点菜单[应用版型],在树中选上“查询BP版型”,如下图:
步骤一:
步骤二:
在版型树上选中[查询BP版型]。
BP端代码示例
在设计BP时,给BP加上版型[查询BP版型],在构造时便会生成查询BP的骨架代码,查询BP的开发人员,只需要在适当的位置按业务逻辑写上相应的代码即可。骨架代码分为两个Partial类。其中第一部份只有一个Do方法,在Do方法中BP实现者要调用第二部份的私有方法DoProcess方法,并将BP的参数作为方法的参数。如下:
internal partial class SOShiplineSumBQueryBPImpementStrategy : BaseStrategy
{
public SOShiplineSumBQueryBPImpementStrategy() { }
public override object Do(object obj)
{
SOShiplineSumBQueryBP bpObj = (SOShiplineSumBQueryBP)obj;
return DoProcess(bpObj.QryInParameter);//BP实现者要加上这句话
}
}
private object DoProcess(UFIDA.U9.Query.QueryCaseBP.QryCommonParaObj bpParameter)
{
UFIDA.UBF.Query.CommonService.QryPaginateService ps =
new UFIDA.UBF.Query.CommonService.QryPaginateService(bpParameter, isNeedTempTable());
if (ps.isProcessBusiness)
{
string oql = DoLogic(bpParameter);
return ps.FindDataByPage(GetEntityFullName(), oqlBuildByTempTable(), oql);
}
else
{
return ps.FindDataByPage();
}
}
internal partial class SOLineSumBQueryBPImpementStrategy
{
//主实体FullName
private string GetEntityFullName()
{
return "UFIDA.U9.SM.SO.SOLine";
}
///
/// 分页内部是否需要使用临时表机制,对于数据量比较小的查询,没有必要采用临时表
/// 缓存第一次查询的结果,每次重查就行了,否则第一次查询时页面加载会慢些。由BP
/// 开发人员自己判断。
///
///
private bool isNeedTempTable()
{
return true;
}//end isTempTable
///
/// 是否基于临时表构造的OQL,对于基于临时表的查询,分页服务内部不需要多语的处理;
/// 基于业务表的查询,则需要。此处由BP开发人员根据实际情况返回正确的值。
///
///
private bool oqlBuildByTempTable()
{
return false;
}//end isNeedMultiLang
///
/// 执行业务逻辑,返回OQL串,由BP开发人员添加代码。
/// 参数bpParameter中带有已选栏目、过滤及排序信息
///
///
private string DoLogic(UFIDA.U9.Query.QueryCaseBP.QryCommonParaObj bpParameter)
{
//根据业务逻辑,返回OQL串
}
代码的第二部份中DoProcess方法,由前面的partial类中的Do方法调用。不需要BP开发人员作任何处理。 需要BP开发人员作处理的是以下几个方法:
方法名称 | 用途 |
GetEntityFullName | 主实体FullName,对于基于临时表的OQL则为临时表表名。 |
isNeedTempTable | 分页内部是否需要使用临时表机制,对于数据量比较小的查询,没有必要采用临时表缓存第一次查询的结果,每次重查就行了,否则第一次查询时页面加载会慢些。由BP开发人员自己判断。 |
oqlBuildByTempTable | 是否基于临时表构造的OQL,对于基于临时表的查询,分页服务内部不需要多语的处理;基于业务表的查询,则需要。此处由BP开发人员根据实际情况返回正确的值。 |
DoLogic | 执行业务逻辑,返回OQL串,由BP开发人员添加代码。 参数bpParameter中带有已选栏目、过滤及排序信息。 |
辅助工具
如果所设计的查询DTO中的属性来源于多个实体,字段多,实体间关系复杂,则可以使用SimpleOqlTool来拼接OQL语句。SimpleOqlTool的使用方法与报表DataCommand中的DS设计相同。这里可以借用报表开发工具中的DataCommand代码生成工具,便捷的处理DTO属性名称和实体字段的对应关系。比如,由辅助工具生成的代码片断如下:
///
/// 销售订单计划行.交期 DateTime
///
public readonly static string SOShipline_RequireDate = "SOShipline_RequireDate";
///
/// 销售订单计划行.数量2 Decimal
///
public readonly staticstring SOShipline_ShipPlanQtyTBU = "SOShipline_ShipPlanQtyTBU";
// 销售订单计划行.交期 DateTime
map.Add(SOShipline_RequireDate, "SOShipline.RequireDate");
// 销售订单计划行.数量2 Decimal
map.Add(SOShipline_ShipPlanQtyTBU, "SOShipline.ShipPlanQtyTBU");
其中,SOShipline_RequireDate和SOShipline_ShipPlanQtyTBU就是我们在DTO定义的属性名称
SOShipline.RequireDate与SOShipline.ShipPlanQtyTBU就是实体的字段
那么,最后通过工具拼接成OQL语句会是这样的:
Select SOShipline.RequireDate as SOShipline_RequireDate, SOShipline.ShipPlanQtyTBU as SOShipline_ShipPlanQtyTBU,… from UFIDA::U9::SM::SO::SOShipline as SOShipline
这样就建立起了DTO属性名称与实体字段的对应关系,并且通过这个辅助工具生成代码,能极小减轻我们的工作量。再次强调,DTO设计期的字段名称要与辅助工具中定义的别名一致。
在UBF中打开一个报表,然后选择“报表—DataCommand工具集—DataCommand代码生成”
弹出“解决方案对话框”
1. 服务组名称:由于我们只是借用这个报表工具生成代码,所以服务组名可以随意选一个。
2 生成路径:生成的报表项目的存放路径。
3 DataCommand模型:对于查询开发,不需要选择该项
点击“下一步”弹出 选择字段信息对话框
点击“选择字段”按钮 ,弹出 选择实体信息对话框。
在实体名称中输入要查询的实体,点击“查询按钮”,列表中出现你选择的实体信息。
在DataGrid中双击你要使用的实体,在下面的属性DataGrid中,就会列出该实体的全部属性。
在实体名称中,输入所需的,如Person,则会将与实体名称中包含Person的都列出来。
然后双击一个指定的实体,则会显示出该实体的全部字段。
这里面关键的一点是:要仔细写出各个字段的别名,这个别名要与DTO设计中的字段名一致。(这点一定要注意)
如下图:
注意: 粗体部分表示可以双击,进入该实体或者属性类型来选择它下面的字段属性。
选择实体字段的规则:
基本属性:作为当前实体的一个字段。
实体属性:自动选择实体的ID,Code,Name(没有就不取)
属性类型:自动取属性类型下的所有属性,如果该属性又是实体则取该实体的Code,Name属性
模式匹配:
在模式匹配文本框中输入模式字符串,点击匹配,在属性DataGrid中就会列出匹配的字段信息
点击显示全部属性,就会显示出该实体的全部属性。
选中DataGrid的多行后,在 DataGrid的“选中”列头上右击鼠标,回弹出 选中,取消菜单,进行多选操作。
返回按钮:从子实体中导航到主实体。如:Address.Contact.Enterprise,点击返回时:直接显示 Address的属性
返回上级:从子实体导航到上一级实体。如:Address.Contact.Enterprise,点击返回时:直接显示 Contact的属性
在所有的字段都选择完成后,点击确定按钮
你刚才选择的所有属性就出现在选择字段对话框中的DataGrid中了。如下图:
这个画面中的CheckBox框,对查询开发没有用过,点击下一下跳过即可。
操作提示:
1 在DataGrid的行上双击会弹出选择实体属性对话框,并在实体属性DataGrid中列出实体全称的末级实体的所有属性。(双击当前行进入末级实体选择界面)
2 先选择DataGrid 的多行,在 每一个带CheckBox的列上点击右键可以对选择的多行进行多选操作
3 删除多行:
选择DataGrid的多行,直接按键盘上的Delete键,弹出是否删除的确认框,选择是就会删除所选的行。
点击下一步 弹出 DataCommand信息对话框。
在该对话框中输入DataSource 名称 ,对于查询开发来说,我们只需要生成DataSource即可,点击下一步。
点击下一步 弹出信息确认对话框。
在该对话框中如果你选择了只生成 DataSoruce复选框 ,则将只生成DataSource .
在信息确认界面,如果你确认前面的选择无误后,
点击完成。稍等片刻 ,代码生成完成。
如果你选择了代码生成完成后自动打开 本项目复选框 ,将自动打开该项目。
将生成的字段映射部分代码copy到查询BP中。需要copy的代码有:
#region 实体字段别名定义
#region 实体属性对应的别名定义
。。。
。。。
。。。
#endregion
#endregion
#region 静态构造函数
static XXXX()
{
#region 初始化列栏目名称
。。。
。。。
。。。
#endregion
}
#endregion
具体的使用细节,参见示例:
#region implement strategy
///
/// Impement Implement
///
///
internal partial class QueryBPImpementStrategy : BaseStrategy
{
public QueryBPImpementStrategy() { }
public override object Do(object obj)
{
QueryBP bpObj = (QueryBP)obj;
return DoProcess(bpObj.QryInParameter);
//get business operation context is as follows
//IContext context = ContextManager.Context
//auto generating code end,underside is user custom code
//and if you Implement replace this Exception Code...
//throw new NotImplementedException();
}
}
#region QueryBP Stereotype
internal partial class QueryBPImpementStrategy
{
//实体FullName
private string GetEntityFullName()
{
//TODO:
//return string.Empty;
return "UFIDA.U9.SM.SO.SOShipline";
}
///
/// 分页内部是否需要使用临时表机制,对于数据量比较小的查询,没有必要采用临时表
/// 缓存第一次查询的结果,每次重查就行了,否则第一次查询时页面加载会慢些。由BP
/// 开发人员自己判断。
///
///
private bool isNeedTempTable()
{
return true;
}//end isTempTable
///
/// 是否基于临时表构造的OQL,对于基于临时表的查询,分页服务内部不需要多语的处理;
/// 基于业务表的查询,则需要。此处由BP开发人员根据实际情况返回正确的值。
///
///
private bool oqlBuildByTempTable()
{
return false;
}//end isNeedMultiLang
///
/// 执行业务逻辑,返回OQL串,由BP开发人员添加代码。
/// 参数bpParameter中带有已选栏目、过滤及排序信息
///
///
private string DoLogic(UFIDA.U9.Query.QueryCaseBP.QryCommonParaObj bpParameter)
{
DoMap();
//必须引用UFIDA.UBF.Report.App.Data.dll
UFIDA.UBF.Report.App.Data.SimpleOqlTool simpleTool = new UFIDA.UBF.Report.App.Data.SimpleOqlTool();
//处理栏目,形成Select子句
foreach (QryColumnItem columnitem in bpParameter.QryColumnItems)
{
string columAlias = GetParseName(this.map[columnitem.ColumnAlias]);
simpleTool.AddSelect(columAlias, columnitem.ColumnAlias);
}
//将排序项加入栏目
foreach (QrySortItem sortItem in bpParameter.QrySortItems)
{
simpleTool.AddSelect(GetParseName(this.map[sortItem.ColumnName]), sortItem.ColumnName);
}
//ID
string alias = GetParseName(ID);
simpleTool.AddSelect(alias, ID);
//SOLine_ID
alias = GetParseName(this.map[SOLine_ID]);
simpleTool.AddSelect(alias, SOLine_ID);
//Org_ID
alias = GetParseName(this.map[Org_ID]);
simpleTool.AddSelect(alias, Org_ID);
//SOLine_SO_ID
alias = GetParseName(this.map[SOLine_SO_ID]);
simpleTool.AddSelect(alias, SOLine_SO_ID);
#region //精度
//销售单位_精度_精度
alias = GetParseName(this.map[TU_Round_Precision]);
simpleTool.AddSelect(alias, TU_Round_Precision);
//销售单位_精度_舍入类型
alias = GetParseName(this.map[TU_Round_RoundType]);
simpleTool.AddSelect(alias, TU_Round_RoundType);
//销售单位_精度_舍入值
alias = GetParseName(this.map[TU_Round_RoundValue]);
simpleTool.AddSelect(alias, TU_Round_RoundValue);
//销售基准单位_精度_精度
alias = GetParseName(this.map[TBU_Round_Precision]);
simpleTool.AddSelect(alias, TBU_Round_Precision);
//销售基准单位_精度_舍入类型
alias = GetParseName(this.map[TBU_Round_RoundType]);
simpleTool.AddSelect(alias, TBU_Round_RoundType);
//销售基准单位_精度_舍入值
alias = GetParseName(this.map[TBU_Round_RoundValue]);
simpleTool.AddSelect(alias, TBU_Round_RoundValue);
#endregion
//处理条件,形成Where子句
if (bpParameter.FilterOpath != "")
simpleTool.AddCondition(bpParameter.FilterOpath);
else
simpleTool.AddCondition("1=0");
//3.处理Order
//foreach (QrySortItem sortItem in bpParameter.QrySortItems)
//{
// if (this.map[sortItem.ColumnName] != null && this.map[sortItem.ColumnName] != "")
// {
// string sortName = GetParseName(map[sortItem.ColumnName]);
// if (sortItem.OrderType == UFIDA.U9.Query.QueryCaseBE.OrderType.Ascend)
// simpleTool.AddOrder(sortName, true);
// else
// simpleTool.AddOrder(sortName, false);
// }
//}
//处理From部份,形成From子句
simpleTool.SetFromClause(" UFIDA::U9::SM::SO::SO SO left join UFIDA::U9::SM::SO::SOLine SOLine on SO.ID = SOLine.SO "
+ " left join UFIDA::U9::SM::SO::SOShipline SOShipLine on SOLine.ID=SOShipLine.SOLine ");
//获取OQL串
string selectResult = simpleTool.GetOqlString();
//订单版本处理
StringBuilder sbRel = new StringBuilder(2048);
string selectResultHis = selectResult.Replace("UFIDA::U9::SM::SO::SOShipline SOShipLine", "UFIDA::U9::SM::SO::SOShiplineHis SOShipLine");
selectResultHis = selectResultHis.Replace("UFIDA::U9::SM::SO::SOLine SOLine", "UFIDA::U9::SM::SO::SOLineHis SOLine");
selectResultHis = selectResultHis.Replace("UFIDA::U9::SM::SO::SO SO", "UFIDA::U9::SM::SO::SOHis SO");
sbRel.Append("select * from ( ");
sbRel.Append(selectResult);
sbRel.Append(" union all ");
sbRel.Append(selectResultHis);
sbRel.Append(" ) as A ");
//处理排序
if (bpParameter.QrySortItems.Count > 0)
sbRel.Append(" order by ");
foreach (QrySortItem sortItem in bpParameter.QrySortItems)
{
if (sortItem.OrderType == UFIDA.U9.Query.QueryCaseBE.OrderType.Ascend)
{
sbRel.Append(sortItem.ColumnName);
sbRel.Append(" asc ");
}
else
{
sbRel.Append(sortItem.ColumnName);
sbRel.Append(" desc ");
}
sbRel.Append(",");
}
selectResult = sbRel.ToString();
if (selectResult.EndsWith(","))
selectResult = selectResult.Substring(0, selectResult.Length - 1);
return selectResult;
} //end DoLogic
///
/// 获取解析后的字段名称
///
///
///
private string GetParseName(string ItemName)
{
string name = ItemName;
if (name.StartsWith("SOLine.SO"))
name = name.Replace("SOLine.SO", "SO");
//else if (name.StartsWith("SO"))
// name = name;
else
name = "SOShipLine." + name;
return name;
}
///
/// 这部份代码查询开发人员不要作修改
/// 删除Do方法中的
/// throw new NotImplementedException();
/// 在Do方法中直接加上一句:
/// return DoProcess(bpObj.QryInParameter);
///
///
///
private object DoProcess(UFIDA.U9.Query.QueryCaseBP.QryCommonParaObj bpParameter)
{
UFIDA.UBF.Query.CommonService.QryPaginateService ps = new UFIDA.UBF.Query.CommonService.QryPaginateService(bpParameter, isNeedTempTable());
if (ps.isProcessBusiness)
{
string oql = DoLogic(bpParameter);
return ps.FindDataByPage(GetEntityFullName(), oqlBuildByTempTable(), oql);
}
else
{
return ps.FindDataByPage();
}
}
}
internal partial class QueryBPImpementStrategy
{
private IDictionary map = new Dictionary();
#region 实体属性对应的别名定义
public readonly static string ID = "ID";
public readonly static string Org_Name = "Org_Name";
public readonly static string SOLine_SO_DocNo = "SOLine_SO_DocNo";
public readonly static string SOLine_SO_BusinessDate = "SOLine_SO_BusinessDate";
public readonly static string SOLine_SO_OrderBy_Name = "SOLine_SO_OrderBy_Name";
public readonly static string SOLine_DocLineNo = "SOLine_DocLineNo";
public readonly static string SOLine_ItemInfo_ItemName = "SOLine_ItemInfo_ItemName";
public readonly static string SOLine_ItemInfo_ItemCode = "SOLine_ItemInfo_ItemCode";
public readonly static string DocSubLineNo = "DocSubLineNo";
public readonly static string ShipToSite_Name = "ShipToSite_Name";
public readonly static string ItemInfo_ItemName = "ItemInfo_ItemName";
public readonly static string ItemInfo_ItemCode = "ItemInfo_ItemCode";
public readonly static string SupplySource = "SupplySource";
public readonly static string SupplyOrg_Name = "SupplyOrg_Name";
public readonly static string WH_Name = "WH_Name";
public readonly static string DeliveryDate = "DeliveryDate";
public readonly static string ShipPlanQtyTU = "ShipPlanQtyTU";
public readonly static string ShipPlanQtyTBU = "ShipPlanQtyTBU";
public readonly static string SOLine_ID = "SOLine_ID";
public readonly static string Org_ID = "Org_ID";
public readonly static string TU_Round_Precision = "TU_Round_Precision";
public readonly static string TU_Round_RoundType = "TU_Round_RoundType";
public readonly static string TU_Round_RoundValue = "TU_Round_RoundValue";
public readonly static string TBU_Round_Precision = "TBU_Round_Precision";
public readonly static string TBU_Round_RoundType = "TBU_Round_RoundType";
public readonly static string TBU_Round_RoundValue = "TBU_Round_RoundValue";
public readonly static string SOLine_SO_ID = "SOLine_SO_ID";
public readonly static string Seiban_SeibanNO = "Seiban_SeibanNO";
#endregion
private void DoMap()
{
//ID
map.Add(ID, "ID");
//组织
map.Add(Org_Name, "Org.Name");
//订单号
map.Add(SOLine_SO_DocNo, "SOLine.SO.DocNo");
//订单日期
map.Add(SOLine_SO_BusinessDate, "SOLine.SO.BusinessDate");
//订货客户名称
map.Add(SOLine_SO_OrderBy_Name, "SOLine.SO.OrderBy.Name");
//订单行号
map.Add(SOLine_DocLineNo, "SOLine.DocLineNo");
//订单行.品名
map.Add(SOLine_ItemInfo_ItemName, "SOLine.ItemInfo.ItemName");
//订单行.料号
map.Add(SOLine_ItemInfo_ItemCode, "SOLine.ItemInfo.ItemCode");
//订单子行号
map.Add(DocSubLineNo, "DocSubLineNo");
//收货位置
map.Add(ShipToSite_Name, "ShipToSite.Name");
//订单子行.品名
map.Add(ItemInfo_ItemName, "ItemInfo.ItemName");
//订单子行.料号
map.Add(ItemInfo_ItemCode, "ItemInfo.ItemCode");
//供应来源
map.Add(SupplySource, "SupplySource");
//供应组织
map.Add(SupplyOrg_Name, "SupplyOrg.Name");
//存储地点
map.Add(WH_Name, "WH.Name");
//承诺日期
map.Add(DeliveryDate, "DeliveryDate");
//数量1
map.Add(ShipPlanQtyTU, "ShipPlanQtyTU");
//数量2
map.Add(ShipPlanQtyTBU, "ShipPlanQtyTBU");
//ID
map.Add(SOLine_ID, "SOLine.ID");
//ID
map.Add(Org_ID, "Org.ID");
//销售单位_精度_精度
map.Add(TU_Round_Precision, "TU.Round.Precision");
//销售单位_精度_舍入类型
map.Add(TU_Round_RoundType, "TU.Round.RoundType");
//销售单位_精度_舍入值
map.Add(TU_Round_RoundValue, "TU.Round.RoundValue");
//销售基准单位_精度_精度
map.Add(TBU_Round_Precision, "TBU.Round.Precision");
//销售基准单位_精度_舍入类型
map.Add(TBU_Round_RoundType, "TBU.Round.RoundType");
//销售基准单位_精度_舍入值
map.Add(TBU_Round_RoundValue, "TBU.Round.RoundValue");
//ID
map.Add(SOLine_SO_ID, "SOLine.SO.ID");
//赛班
map.Add(Seiban_SeibanNO, "Seiban.SeibanNO");
}
}
#endregion
使用EntityViewQuery来处理System.Data.DataTable
如果对于一些复杂的查询,不能用一个完整的OQL表达出来,则需要使用临时表的方法,做二次查询,或在DataTable中计算。
可以使用EntityViewQuery来创建和使用临时表。使用该对象之前,需要将连接打开,代码如下:
IDbConnection sqlCon = DatabaseManager.GetCurrentConnection();
if (sqlCon.State == ConnectionState.Closed)
{
sqlCon.Open();
DatabaseManager.CurrentConnection = sqlCon;
}
EntityViewQuery viewQuery = new EntityViewQuery();
如果大家有用EntityDataQuery查询出结果,进行数据处理,然后把数据写到临时表中的这样一个过程,要注意加上以下红色标明的那行代码。否则如果用到多语字段,会把当前系统支持的所有多语记录都查出来。另外如果能用EntityViewQuery ,尽可能的用EntityViewQuery去实现。如下面黄色背景所示:
private void GetProductCostRecordToTable()
{
EntityDataQuery productQry = CA.CalculateCost.ProductCost.Finder.CreateDataQuery();
productQry.QOptions.MultiLangOption = new GlobalizationContext(ContextManager.CultureName);
//获取OQL串
StringBuilder productoql = new StringBuilder();
productoql.Append(" ID as ID, ");
productoql.Append("Org.Name as Org_Name, ");
productoql.Append("SOB.Name as SOB_Name, ");
productoql.Append("SOBPeriod.Code as SOBPeriod_Code, ");
productoql.Append("CostField.Name as CostField_Name, ");
productoql.Append("CostType.Name as CostType_Name, ");
productoql.Append("IsBooking as IsBooking, ");
productoql.Append("Product.Name as Product_Name, ");
productoql.Append("Cost.OverheadPriorCost as Cost_OverheadPriorCost, Cost.LaborPriorCost as Cost_LaborPriorCost, Cost.MaterialPriorCost as Cost_MaterialPriorCost, Cost.MachinePriorCost as Cost_MachinePriorCost, Cost.OverheadCurrentCost as Cost_OverheadCurrentCost, Cost.MaterialCurrentCost as Cost_MaterialCurrentCost, Cost.MachineCurrentCost as Cost_MachineCurrentCost, Cost.LaborCurrentCost as Cost_LaborCurrentCost, Cost.SubcontractPriorCost as Cost_SubcontractPriorCost, Cost.SubcontractCurrentCost as Cost_SubcontractCurrentCost ");
productQry.Select(productoql.ToString());
DataSet ds = productQry.FindDataSet(this.QryOqlWhere);
AddDataToTable(ds);
}
UI端代码示例
Action中代码
主要是定义DTOFullName,使用DTOQueryStrategyImpl来获取CaseModel,使用GridNavigateAction来加载第一页
public partial class SalerOrderSumBQryUIModelAction
{
public string QryModelID = "2b14cc70-eb35-4ac3-bffa-887f67a0362e";
string DTOFullName = "UFIDA.U9.SM.SMQueryBP.SOSumBQueryDTO";//定义DTO实体全名
。。。
。。。
。。。
//输出
private void OnOutPut_Extend(object sender, UIActionEventArgs e)
{
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy proxy = new UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy();
QryBPExportService qryExportservice = new QryBPExportService(UIGrid, proxy, "QryInParameter", this.CurrentPart.NameValues["MOID"].ToString());
IExportSettings settings = ExportServiceFactory.GetInstance().CreateExportSettingsObject();
settings.PrintData = qryExportservice.GetResultSet();
e.Tag = settings;
this.OnOutPut_DefaultImpl(sender, e);
}
//打印
private void OnPrint_Extend(object sender, UIActionEventArgs e)
{
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy proxy = new UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy();
//QryBPExportService构造函数的说明,请参见下文
QryBPExportService qryExportservice = new QryBPExportService(UIGrid, proxy, "QryInParameter", this.CurrentPart.NameValues["MOID"].ToString());
IExportSettings settings = ExportServiceFactory.GetInstance().CreateExportSettingsObject();
settings.PrintData = qryExportservice.GetResultSet();
e.Tag = settings;
this.OnPrint_DefaultImpl(sender, e);
}
//数据加载的扩展
private void this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
//使用DTO查询策略
DTOQueryStrategyImpl dtoQryStrategyImpl = new DTOQueryStrategyImpl(this.CurrentState, DTOFullName, QryModelID,this.MainView, UIGrid);
dtoQryStrategyImpl.Adjust();
this.MainView.Clear();
//调用BP,加载第一页的数据
UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy proxy = new UFIDA.U9.MO.MO.Proxy.ParentSubMOBQryBPProxy();
GridNavigateAction action = new GridNavigateAction(UIGrid, proxy, "QryInParameter");
//如果是消费者画面,则需要处理Webpart关联传入的参数,如下:
action.FilterOpath = this.CurrentPart.NameValues["MOID"].ToString();
action.LoadFirstPage();
if (this.MainView.Records.Count == 0)
{
this.CurrentPart.ShowWindowStatus(UFIDA.U9.UI.PDHelper.PDResource.GetNoRecordSucessInfo());
}
else
{
this.CurrentPart.ShowWindowStatus(UFIDA.U9.UI.PDHelper.PDResource.GetFindSucessInfo());
}
}
public void InitCaseModel()
{
QryService.ClearSession((UFSoft.UBF.UI.FormProcess.BaseWebForm)(this.CurrentPart));
IUFDataGrid UIGrid = this.CurrentPart.GetUFControlByName(this.CurrentPart.TopLevelContainer, "DataGrid1") as IUFDataGrid;
//使用DTO查询策略
DTOQueryStrategyImpl dtoQryStrategyImpl = new DTOQueryStrategyImpl(this.CurrentState, DTOFullName, QryModelID,this.MainView, UIGrid);
CaseModel caseModel = dtoQryStrategyImpl.GetQryModel();
QryService.SetCaseModelToSession((UFSoft.UBF.UI.FormProcess.BaseWebForm)(this.CurrentPart), caseModel);
}
}
QryBPExportService构造函数说明
public QryBPExportService(IUFDataGrid grid,object bp, string bpPropertyName,string filterOpath)
grid:查询列表画面中的UIGrid
bp:BP的代理(proxy)
bpPropertyName:设计BP时,“查询BP通用入参DTO”的名称
filterOpath:存放不能通过“查询BP通用入参DTO”来传递的查询条件,比如从其他界面传递过来的参数等。
WebPart中代码
(定义和实现翻页事件)
public void After UpdatePanelUpdateMode.Always;
//this.IsProviding = true;//如果在Webpart关联中,本WebPart是提供者,则需要加入这段话
//定义翻页事件,需要加入引用using UFSoft.UBF.UI.WebControlAdapter;
((UFWebDataGridAdapter)this.DataGrid1).GridMakePageEventHandler += new GridMakePageDelegate(SOListUIFormWebPart_GridMakePageEventHandler);
}
//翻页事件
void SOListUIFormWebPart_GridMakePageEventHandler(object sender, GridMakePageEventArgs e)
{
GridNavigateAction action = new GridNavigateAction(this.DataGrid1, new SOSumBQueryBPProxy(), "QryInParameter");
//如果是消费者画面,则需要根据情况来处理“关联参数”,即处理action.FilterOpath,如果开发人员自定义了FilterOpath,那么在这里的翻页事件中,也要重新转入
Action.FilterOpath = "某种条件"
switch (e.Action)
{
case enumPageAction.FirstPage:
action.FirstPage();
break;
case enumPageAction.PreviousPage:
action.PrevPage();
break;
case enumPageAction.NextPage:
action.NextPage();
break;
case enumPageAction.LastPage:
action.LastPage();
break;
}
this.DataGrid1.PageAction = e.Action;
}
public void BeforeUIModelBinding()
{
//如果条件没能传入到BP中,则是因为没按这个规范来写BeforeUIModelBinding中的代码。[FAQ01]
if (QryService.IsCallInitCaseModel(this.DataGrid1))
{
this.Action.InitCaseModel();
}
if (QryService.IsCallAdjust(this.DataGrid1))
{
this.Action.QueryAdjust();
}
else
{
QryService.SetGridWidthToCase(this.CurrentState, FormID, this.DataGrid1);
}
}
public void AfterUIModelBinding()
{
QryService.BindEnum("DDLCase", this, "2b14cc70-eb35-4ac3-bffa-887f67a0362e");
//添加调整UIGrid的代码
}
查询开发框架
本文2024-08-20 18:35:38发表“u9cloud知识”栏目。
本文链接:https://wenku.my7c.com/article/yonyou-u9cloud-1191.html