二开案例.单据插件.元数据缓存刷新之创建人创建日期丢失
【应用场景】
因不明原因的元数据损坏,导致某些字段的数据丢失。
【注意】
此方案用于元数据被损坏,且无法找到损坏源的特殊场景,属于不得已而为之。仍然建议您尽最大可能找到元数据被损坏的真实原因,只有找到了问题源头,才能根治元数据异常引发的各种灾难性问题。
【案例演示】
销售订单,元数据丢失了创建人,创建日期字段,导致新建订单没有创建人,创建日期,如果有编码规则引用了创建日期字段,还会导致跟根据此编码规则生成的单据编号也有异常。
【实现步骤】
<1> 注册表单插件,模拟采购订单元数据被人为破坏的场景。
using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Util; using System.ComponentModel; using System.Linq; namespace Jac.XkDemo.BOS.Business.PlugIn { /// <summary> /// 【表单插件】创建人创建日期元数据损坏模拟测试 /// </summary> [Description("【表单插件】创建人创建日期元数据损坏模拟测试"), HotUpdate] public class CreateInfoLostTestFormPlugIn : AbstractDynamicFormPlugIn { public override void BarItemClick(BarItemClickEventArgs e) { base.BarItemClick(e); if (e.BarItemKey.Contains("test")) { // 创建人字段 //var field1 = this.View.BillBusinessInfo.GetField("FCreatorId"); //if (field1 != null) //{ // this.View.BillBusinessInfo.Remove(field1); //} var field1_Entity = this.View.BillBusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase("FCreatorId")); if (field1_Entity != null) { this.View.BillBusinessInfo.GetEntity(0).Fields.Remove(field1_Entity); } //var field1_FieldList = this.View.BillBusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase("FCreatorId")); //if (field1_FieldList != null) //{ // this.View.BillBusinessInfo.GetFieldList().Remove(field1_FieldList); //} // 创建日期字段 //var field2 = this.View.BillBusinessInfo.GetField("FCreateDate"); //if (field2 != null) //{ // this.View.BillBusinessInfo.Remove(field2); //} var field2_Entity = this.View.BillBusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase("FCreateDate")); if (field2_Entity != null) { this.View.BillBusinessInfo.GetEntity(0).Fields.Remove(field2_Entity); } //var field2_FieldList = this.View.BillBusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase("FCreateDate")); //if (field2_FieldList != null) //{ // this.View.BillBusinessInfo.GetFieldList().Remove(field2_FieldList); //} } } } }
<2>注册单据插件,用于检测元数据是否有损坏,如果损坏了,清空缓存,重建元数据。
using Kingdee.BOS; using Kingdee.BOS.Cache; using Kingdee.BOS.Core.Bill; using Kingdee.BOS.Core.Bill.PlugIn; using Kingdee.BOS.Core.Bill.PlugIn.Args; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Core.Metadata; using Kingdee.BOS.ServiceHelper; using Kingdee.BOS.Util; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; namespace Jac.XkDemo.BOS.Business.PlugIn { /// <summary> /// 【单据插件】元数据缓存刷新之创建人创建日期丢失 /// </summary> [Description("【单据插件】元数据缓存刷新之创建人创建日期丢失"), HotUpdate] public class ReloadMetadataForCreateInfoLostBillPlugIn : AbstractBillPlugIn { /// <summary> /// 创建人字段标识 /// </summary> private const string CreatorIdFieldKey = "FCreatorId"; /// <summary> /// 创建人字段属性名 /// </summary> private const string CreatorIdPropertyName = "CreatorId"; /// <summary> /// 创建日期字段标识 /// </summary> private const string CreateDateFieldKey = "FCreateDate"; /// <summary> /// 创建日期字段属性名 /// </summary> private const string CreateDatePropertyName = "CreateDate"; public override void AfterCreateModelData(EventArgs e) { base.AfterCreateModelData(e); if (!CheckMetadata(this.View)) { GetNewMetadata(this.View); throw new Exception("创建新数据包后检测到元数据异常,请关闭当前界面后重试!"); } } public override void LoadData(LoadDataEventArgs e) { base.LoadData(e); if (!CheckMetadata(this.View)) { GetNewMetadata(this.View); throw new Exception("加载数据前检测到元数据异常,请关闭当前界面后重试!"); } } public override void AfterLoadData(EventArgs e) { base.AfterLoadData(e); if (!CheckMetadata(this.View)) { GetNewMetadata(this.View); throw new Exception("加载数据后检测到元数据异常,请关闭当前界面后重试!"); } } public override void BeforeDoOperation(BeforeDoOperationEventArgs e) { base.BeforeDoOperation(e); if (!new long[] { 8, 40 }.Contains(e.Operation.FormOperation.OperationId)) { // 只处理暂存和保存 return; } if (!CheckMetadata(this.View)) { GetNewMetadata(this.View); throw new Exception(string.Format("执行操作[{0}]前检测到元数据异常,请关闭当前界面后重试!", e.Operation.FormOperation.OperationName)); } } /// <summary> /// 清除元数据缓存,返回新的元数据 /// </summary> /// <param name="view"></param> /// <returns></returns> private FormMetadata GetNewMetadata(IBillView view) { var ctx = view.Context; var businessInfo = view.BusinessInfo; var formId = businessInfo.GetForm().Id; var layoutId = view.OpenParameter.LayoutId; // 清除元数据缓存 ClearMetaCache(ctx, formId); // 重新加载元数据 var meta = FormMetaDataCache.GetCachedFormMetaData(ctx, formId, layoutId); return meta; } /// <summary> /// 清除元数据(清内存缓存和数据库缓存) /// </summary> /// <param name="ctx"></param> /// <param name="formId"></param> private void ClearMetaCache(Context ctx, string formId) { var ids = new List<string>(); // 获取与当前表单有关系的所有表单Id var sql = string.Format(@"SELECT FID FROM T_META_OBJECTTYPE WHERE FMODELTYPEID<600 AND (FID='{0}' OR FINHERITPATH LIKE '%{0}%')", formId); var objs = DBServiceHelper.ExecuteDynamicObject(ctx, sql); if (objs != null && objs.Count > 0) { ids.AddRange(objs.Select(obj => obj[0].ToString())); } // 获取视图,视图的缓存也要清理 sql = string.Format(@"SELECT b.FID FROM T_META_OBJECTTYPE a JOIN T_META_OBJECTTYPEVIEW b ON a.FID=b.FDEPENDENCYOBJECTID WHERE a.FMODELTYPEID<600 AND (a.FID='{0}' OR a.FINHERITPATH LIKE '%{0}%')", formId); objs = DBServiceHelper.ExecuteDynamicObject(ctx, sql); if (objs != null && objs.Count > 0) { ids.AddRange(objs.Select(obj => obj[0].ToString())); } // 先更新版本号 sql = string.Format("UPDATE T_META_OBJECTTYPE SET FMAINVERSION='{0}' WHERE FID IN ({1})", DateTime.Now.Ticks.ToString(), string.Join(",", ids.Select(o => "'" + o + "'"))); DBServiceHelper.Execute(ctx, sql); // 再删除数据库缓存 sql = string.Format("DELETE FROM T_META_OBJECTTYPECACHE WHERE FID IN ({0})", string.Join(",", ids.Select(o => "'" + o + "'"))); DBServiceHelper.Execute(ctx, sql); // 再删除内存缓存 var kcmgr = KCacheManagerFactory.Instance.GetMetadataCacheManager(ctx); if (kcmgr != null) { foreach (var id in ids) { kcmgr.Remove(id); } } } /// <summary> /// 检查元数据是否正常 /// </summary> /// <param name="view"></param> /// <returns>返回false表示元数据异常</returns> private bool CheckMetadata(IBillView view) { if (view == null) { return true; } // 此处,判断元数据可能存在损坏的场景。 // 创建人字段丢失 if (view.BillBusinessInfo.GetField(CreatorIdFieldKey) == null) { return false; } if (view.BillBusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreatorIdFieldKey)) == null) { return false; } if (view.BillBusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreatorIdFieldKey)) == null) { return false; } // 创建日期字段丢失 if (view.BillBusinessInfo.GetField(CreateDateFieldKey) == null) { return false; } if (view.BillBusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreateDateFieldKey)) == null) { return false; } if (view.BillBusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreateDateFieldKey)) == null) { return false; } if (view.Model != null && view.Model.DataObject != null) { if (!view.Model.DataObject.Contains(CreateDatePropertyName)) { return false; } if (!view.Model.DataObject.Contains(CreatorIdPropertyName)) { return false; } } return true; } } }
<3>注册服务插件,强制给数据异常字段赋值。
using Kingdee.BOS; using Kingdee.BOS.Core.DynamicForm.PlugIn; using Kingdee.BOS.Core.DynamicForm.PlugIn.Args; using Kingdee.BOS.Util; using System; using System.ComponentModel; using System.Linq; namespace Jac.XkDemo.BOS.App.PlugIn { /// <summary> /// 【服务插件】单据保存前创建人创建日期字段必录检查 /// </summary> [Description("【服务插件】单据保存前创建人创建日期字段必录检查"), HotUpdate] public class CreatorMustInputOperationServicePlugIn : AbstractOperationServicePlugIn { /// <summary> /// 创建人字段标识 /// </summary> private const string CreatorIdFieldKey = "FCreatorId"; /// <summary> /// 创建人字段属性名 /// </summary> private const string CreatorIdPropertyName = "CreatorId"; /// <summary> /// 创建日期字段标识 /// </summary> private const string CreateDateFieldKey = "FCreateDate"; /// <summary> /// 创建日期字段属性名 /// </summary> private const string CreateDatePropertyName = "CreateDate"; public override void BeforeExecuteOperationTransaction(BeforeExecuteOperationTransaction e) { base.BeforeExecuteOperationTransaction(e); if (!CheckMetadata()) { throw new KDException("######", "单据保存前服务插件检测到元数据异常,请关闭当前界面后重试!"); } foreach (var obj in e.SelectedRows) { // 如果创建人,创建日期未填写,此处补填 if (obj.DataEntity.Contains(CreatorIdPropertyName + "_Id") && (obj.DataEntity[CreatorIdPropertyName + "_Id"] == null || Convert.ToInt32(obj.DataEntity[CreatorIdPropertyName + "_Id"]) == 0)) { obj.DataEntity[CreatorIdPropertyName + "_Id"] = Context.UserId; } if (obj.DataEntity.Contains(CreateDatePropertyName) && obj.DataEntity[CreateDatePropertyName] == null) { obj.DataEntity[CreateDatePropertyName] = DateTime.Now; } } } /// <summary> /// 检查元数据是否正常 /// </summary> /// <returns>返回false表示元数据异常</returns> private bool CheckMetadata() { // 此处,判断元数据可能存在损坏的场景。 // 创建人字段丢失 if (this.BusinessInfo.GetField(CreatorIdFieldKey) == null) { return false; } if (this.BusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreatorIdFieldKey)) == null) { return false; } if (this.BusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreatorIdFieldKey)) == null) { return false; } // 创建日期字段丢失 if (this.BusinessInfo.GetField(CreateDateFieldKey) == null) { return false; } if (this.BusinessInfo.GetFieldList().FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreateDateFieldKey)) == null) { return false; } if (this.BusinessInfo.GetEntity(0).Fields.FirstOrDefault(o => o.Key.EqualsIgnoreCase(CreateDateFieldKey)) == null) { return false; } return true; } } }
<4>拷贝插件组件到应用站点的WebSite\Bin目录下,重启IIS。
<5>BOSIDE扩展采购订单,注册表单插件,保存操作注册服务插件,保存元数据,开发完毕。
【功能验证】
<1>登录业务站点,打开销售订单新增界面,点test,此时将破坏销售订单的元数据。
<2>重新打开销售订单新增界面,此时录单并保存,系统报错,提示元数据损坏,请重新打开销售订单新增界面。
---------------------------------------------------------------------------------------------------------
【金蝶云星空BOS二次开发案例演示】https://vip.kingdee.com/article/94751030918525696
二开案例.单据插件.元数据缓存刷新之创建人创建日期丢失
【应用场景】因不明原因的元数据损坏,导致某些字段的数据丢失。【注意】此方案用于元数据被损坏,且无法找到损坏源的特殊场景,属于不得已...
点击下载文档
本文2024-09-23 04:01:44发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-162646.html
您需要登录后才可以发表评论, 登录登录 或者 注册
最新文档
热门文章