二开案例.单据插件.单据打开前重新加载元数据
【应用场景】
元数据异常,且几乎无法找到原因的情况下,可选择在合适的时机,强制性的重新生成元数据。
【案例演示】
应收票据,无故多出来两个字段,导致单据保存异常中断。
【实现步骤】
<1>编写单据插件,代码如下。
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.Core.Metadata.ControlElement;
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>
/// 【单据插件】单据打开前重新加载元数据
/// https://vip.kingdee.com/article/239414681620848640
/// </summary>
[Description("【单据插件】单据打开前重新加载元数据"), HotUpdate]
public class ReloadMetadataBeforeOpenBillBillPlugIn : AbstractBillPlugIn
{
private BusinessInfo businessInfo;
private LayoutInfo layoutInfo;
public override void OnSetBusinessInfo(SetBusinessInfoArgs e)
{
base.OnSetBusinessInfo(e);
if (this.View.OpenParameter != null && this.View.OpenParameter.Status != OperationStatus.ADDNEW)
{
// 控制下影响范围,仅在新增单据的时候重新加载元数据
return;
}
var meta = GetNewMetadata(this.View);
if (meta != null)
{
this.businessInfo = meta.BusinessInfo;
this.layoutInfo = meta.GetLayoutInfo();
e.BillBusinessInfo = this.businessInfo;
e.BusinessInfo = this.businessInfo;
}
}
public override void OnSetLayoutInfo(SetLayoutInfoArgs e)
{
base.OnSetLayoutInfo(e);
e.BillLayoutInfo = this.layoutInfo;
e.LayoutInfo = this.layoutInfo;
}
//public override void BeforeCreateModelData(EventArgs e)
//{
// base.BeforeCreateModelData(e);
// if (!CheckMetadata(this.View))
// {
// GetNewMetadata(this.View);
// throw new Exception("创建新数据包前检测到元数据异常,请关闭当前界面后重试!");
// }
//}
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("加载数据后检测到元数据异常,请关闭当前界面后重试!");
}
}
/// <summary>
/// 清除元数据缓存,返回新的元数据
/// </summary>
/// <param name="view"></param>
/// <returns></returns>
private static 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 static 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></returns>
private static bool CheckMetadata(IBillView view)
{
var dy = view.BillBusinessInfo.GetDynamicObjectType();
if (dy.Properties.Contains("Number") && dy.Properties.Contains("FCheckBox"))
{
return false;
}
dy = view.BusinessInfo.GetDynamicObjectType();
if (dy.Properties.Contains("Number") && dy.Properties.Contains("FCheckBox"))
{
return false;
}
dy = view.Model.BillBusinessInfo.GetDynamicObjectType();
if (dy.Properties.Contains("Number") && dy.Properties.Contains("FCheckBox"))
{
return false;
}
dy = view.Model.BusinessInfo.GetDynamicObjectType();
if (dy.Properties.Contains("Number") && dy.Properties.Contains("FCheckBox"))
{
return false;
}
return true;
}
}
}
<2>拷贝插件组件到应用站点的WebSite\Bin目录下,重启IIS。
<3>BOSIDE扩展应收票据,注册表单插件,保存元数据,开发完毕。
---------------------------------------------------------------------------------------------------------
【金蝶云星空BOS二次开发案例演示】https://vip.kingdee.com/article/94751030918525696
二开案例.单据插件.单据打开前重新加载元数据
本文2024-09-23 04:18:38发表“云星空知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-k3cloud-164488.html