纯代码生成基础资料/单据

场景:
1、客户第三方数据保存到中间表,需要从中间表读取数据写入到星空公有云;
2、客户有2个基础资料、12张单据的数据需要同步到星空系统;
3、客户一个月的数据量大概80万条记录(单据比较特殊,只有表头信息),其中有一大半是在月底一次性同步;
开发思路:
| 开发方案 | 标题 | 优点 | 缺点 |
| 方案一 | 后台直接写数据库 | 性能最优 | 如果单据上后续调整计算逻辑,需要修改插件代码 |
| 方案二(本示例方案) | 建立模型调用单据保存方法 | 单据计算逻辑可以自适应,保存逻辑调整也可以自适应 | 性能没直接写数据库快 |
| 方案三 | 调用API接口进行保存 | (未尝试) | (未尝试) |
性能测试结果(开启5线程):
| 序号 | 流程名称 | 表记录基数 | 同步记录数 | 耗时(秒) | 平均(秒) | |
| 1 | 基础资料(新增或更新) | 无 | 3118 | 61 | 0.0196 | |
| 2 | 单据(只新增) | 1600万 | 384129 | 3627 | 0.0094 | |
| 3 | 单据(只新增) | 几十万 | 373969 | 532 | 0.0014 | |
| 4 | 单据(判断原单据不存在则新增) 2021-08-03更新 | 一百多万 | 415860 | 4860 | 0.0117 |
详细插件代码示例:
1、引用(不是所有必须的,先使用后删除不需要的就行)
using Kingdee.BOS; using Kingdee.BOS.App.Data; using Kingdee.BOS.Core; using Kingdee.BOS.Core.Bill; using Kingdee.BOS.Core.DynamicForm; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.Core.Metadata.FormElement; using Kingdee.BOS.Core.Validation; using Kingdee.BOS.Orm; using Kingdee.BOS.Orm.DataEntity; using Kingdee.BOS.ServiceHelper; using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading;
2、保存一张单据的入口函数,
/// <summary>
/// 根据业务对象类型
/// </summary>
/// <param name="ctx">星空上下文</param>
/// <param name="objectTypeId">单据类型,该参数非必要,根据客户需求增加用作区分不同单据的处理</param>
/// <param name="mySqlDR">数据集,该参数非必要,本例是对接mySql,结合单据类型在后面填充字段值时使用</param>
/// <param name="PkValue">单据ID值,该参数非必要,外面读取单据是否已经存在</param>
/// <param name="strErrorList">收集错误信息,该参数非必要,根据开发设计用作日志记录</param>
/// <param name="FillBillPropertys">做了个填充字段值的方法指针</param>
public void ImportBill(Context ctx, string objectTypeId, MySqlDataReader mySqlDR, Object PkValue, ref List<string> strErrorList, Action<IBillView, string, MySqlDataReader, List<string>> FillBillPropertys)
{
try
{
// 构建一个IBillView实例,通过此实例,可以方便的填写业务对象各属性
IBillView billView = CreateBillView(ctx, objectTypeId, PkValue,ref strErrorList);
if (billView == null)
{
strErrorList.Add("构建一个IBillView实例出现异常,请再尝试一次同步。");
return;
}
// 新建一个空白实例
((IBillViewService)billView).LoadData();
// 触发插件的OnLoad事件:
// 组织控制基类插件,在OnLoad事件中,对主业务组织改变是否提示选项进行初始化。
// 如果不触发OnLoad事件,会导致主业务组织赋值不成功
DynamicFormViewPlugInProxy eventProxy = billView.GetService<DynamicFormViewPlugInProxy>();
eventProxy.FireOnLoad();
// 填写业务对象实例各属性
FillBillPropertys(billView, objectTypeId, mySqlDR, strErrorList);
//同步赋值有问题,就直接退出
if (strErrorList.Count > 0)
{
return;
}
// 保存业务对象实例
List<ValidationErrorInfo> errorList = new List<ValidationErrorInfo>();
SaveBill(ctx, billView, OperateOption.Create(), out errorList);
foreach (ValidationErrorInfo item in errorList)
{
strErrorList.Add(item.Message);
}
}
catch (Exception ex)
{
strErrorList.Add(ex.Message);
}
}3、创建单据视图(该方法基本不用调整)
/// <summary>
/// 创建一个单据视图,后续将利用此视图的各种方法,设置业务对象字段值
/// </summary>
/// <remarks>
/// 理论上,也可以直接修改业务对象的数据包达成修改数据的目的
/// 但是,利用单据视图更具有优势:
/// 1. 视图会自动触发插件,这样逻辑更加完整;
/// 2. 视图会自动利用单据元数据,填写字段默认值,不用担心字段值不符合逻辑;
/// 3. 字段改动,会触发实体服务规则;
///
/// 而手工修改数据包的方式,所有的字段值均需要自行填写,非常麻烦
/// </remarks>
private IBillView CreateBillView(Context ctx, string objectTypeId, object PkValue, ref List<string> strErrorList)
{
try
{
// 读取业务对象的元数据
FormMetadata meta = MetaDataServiceHelper.Load(ctx, objectTypeId) as FormMetadata;
//业务对象整体信息
Form form = meta.BusinessInfo.GetForm();
// 动态领域模型服务提供类,通过此类,构建MVC实例
var provider = form.GetFormServiceProvider();
// 创建用于引入数据的单据view
Type type = Type.GetType("Kingdee.BOS.Web.Import.ImportBillView,Kingdee.BOS.Web");
var billView = (IDynamicFormViewService)Activator.CreateInstance(type);
// 开始初始化billView:
// 创建视图加载参数对象,指定各种参数,如FormId, 视图(LayoutId)等
BillOpenParameter openParam = CreateOpenParameter(ctx, meta, PkValue);
if (openParam == null)
{
return null;
}
billView.Initialize(openParam, provider);
return billView as IBillView;
}
catch (Exception ex)
{
strErrorList.Add(ex.Message);
return null;
}
}4、创建视图加载参数对象(该方法基本不用调整)
/// <summary>
/// 创建视图加载参数对象,指定各种初始化视图时,需要指定的属性
/// </summary>
/// <param name="meta">元数据</param>
/// <returns>视图加载参数对象</returns>
private BillOpenParameter CreateOpenParameter(Context ctx, FormMetadata meta, object PkValue)
{
try
{
Form form = meta.BusinessInfo.GetForm();
// 指定FormId, LayoutId
BillOpenParameter openParam = new BillOpenParameter(form.Id, meta.GetLayoutInfo().Id);
// 数据库上下文
openParam.Context = ctx;
// 本单据模型使用的MVC框架
openParam.ServiceName = form.FormServiceName;
// 随机产生一个不重复的PageId,作为视图的标识
openParam.PageId = Guid.NewGuid().ToString();
// 元数据
openParam.FormMetaData = meta;
// 界面状态:新增 (修改、查看)
openParam.Status = OperationStatus.ADDNEW;
openParam.PkValue = null;
// 单据主键
if (PkValue != null && Convert.ToInt64(PkValue) > 0)
{
openParam.PkValue = PkValue;
openParam.Status = OperationStatus.EDIT;
}
// 界面创建目的:普通无特殊目的 (为工作流、为下推、为复制等)
openParam.CreateFrom = CreateFrom.Default;
// 基础资料分组维度:基础资料允许添加多个分组字段,每个分组字段会有一个分组维度
// 具体分组维度Id,请参阅 form.FormGroups 属性
openParam.GroupId = "";
// 基础资料分组:如果需要为新建的基础资料指定所在分组,请设置此属性
openParam.ParentId = 0;
// 单据类型
openParam.DefaultBillTypeId = "";
// 业务流程
openParam.DefaultBusinessFlowId = "";
// 主业务组织改变时,不用弹出提示界面
openParam.SetCustomParameter("ShowConfirmDialogWhenChangeOrg", false);
// 插件
List<AbstractDynamicFormPlugIn> plugs = form.CreateFormPlugIns();
openParam.SetCustomParameter(FormConst.PlugIns, plugs);
PreOpenFormEventArgs args = new PreOpenFormEventArgs(ctx, openParam);
//foreach (var plug in plugs)
//{// 触发插件PreOpenForm事件,供插件确认是否允许打开界面
// plug.PreOpenForm(args);
//}
if (args.Cancel == true)
{// 插件不允许打开界面
// 本案例不理会插件的诉求,继续....
}
// 返回
return openParam;
}
catch (Exception)
{
return null;
}
}5、给业务对象各属性赋值,根据不同的业务对象类型(自定义的),分别调用不同方法,方便管理
/// <summary>
/// 各属性赋值,填写到IBillView当前所管理的业务对象
/// </summary>
/// <param name="billView"></param>
private static void FillBillPropertys(IBillView billView, string objectTypeId, MySqlDataReader mySqlDR, List<string> strErrorList)
{
switch (objectTypeId)
{
case "xxx":
{
FillBillPropertys_xxx(billView, objectTypeId, mySqlDR, strErrorList);
}
break;
case "yyy":
case "zzz":
case "PSEA_PurAdvance_buffet":
{
FillBillPropertys_yyyzzz(billView, objectTypeId, mySqlDR, strErrorList);
}
break;
default:
break;
}
#region 赋值示例
//基础资料:填写ID或者编码
//dynamicObject = this.View.Model.GetValue("F_ZHMS_OrgId") as DynamicObject;
//setValue = Convert.ToString(dynamicObject["Number"]);
//dynamicFormView.SetItemValueByID("FCreateOrgId", 1, 0)
//dynamicFormView.SetItemValueByNumber("FCreateOrgId", "1", 0)
//辅助资料:填写编码
//dynamicObject = this.View.Model.GetValue("F_ZHMS_TaxType") as DynamicObject;
//setValue = Convert.ToString(dynamicObject["FNumber"]);
//dynamicFormView.SetItemValueByNumber("FTaxType", setValue, 0);
//分组:填写编码
//dynamicObject = this.View.Model.GetValue("F_ZHMS_MaterialGroup") as DynamicObject;
//setValue = Convert.ToString(dynamicObject["Number"]);
//dynamicFormView.UpdateValue("FMaterialGroup", 0, setValue);
//文本:填写内容
//setValue = Convert.ToString(this.View.Model.GetValue("FDescription", thisRowIndex));
//dynamicFormView.UpdateValue("FDescription", 0, "描述(JD-001)");
// 下拉列纯代码生成基础资料/单据
场景:1、客户第三方数据保存到中间表,需要从中间表读取数据写入到星空公有云;2、客户有2个基础资料、12张单据的数据需要同步到星空系统...
点击下载文档文档为doc格式
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。
上一篇
已经是第一篇



