关于%Dictionary.CompiledClass类在实际业务中的一些应用
简单分享下在医院实际业务过程中%Dictionary.CompiledClass的一些应用。
一,Query查询出来的数据直接存表。
我们经常会遇到一些突如其来的检查,如:飞行检查,审计检查等等,往往一下子要查询几年的各种数据,每种数据涉及字段还非常多,数据之间还要求对上,查询耗时长,数据对比难度大,此时,我们需要把查询出来的数据直接存到临时表,数据核对和修改直接在临时表中完成,核对好的数据直接在sqldbx或者水滴等查询工具中整表导出,效率会高一些。
具体实现:按照数据要求,把表建好,Query输出字段和表字段顺序一致,按日期每天调用Query查询和插入,记录异常数据,后续单独处理。
优点:效率明显提高,数据核对和修改、导出很方便,避免了数据量大,多次查询耗时长问题。
缺点:数据量大会占用存储,记得删。
// W ##CLASS(lizw.CloseCycleData).insertDayByDay("2022-01-01","2022-06-30")
ClassMethod insertDayByDay(sd, ed)
{
k ^tmplzw("insertFromQyeryTestpara",$j)
S classOBJ=##class(%Dictionary.CompiledClass).%OpenId("lizw.User.CloseCycleDateTime") //##class(lizw.User.CloseCycleDateTime).%New()
if (classOBJ.%IsA("%Library.Persistent")||(classOBJ.%IsA("%RegisteredObject"))){
s className=classOBJ.Name
s pkgName=classOBJ.SqlSchemaName //%PackageName()
s key=""
s:$d(^oddCOM(className)) ClassName=className
q:ClassName=""
f {
s key=$o(^oddCOM(ClassName,"a",key))
q:key=""
i $e(key,1)="%"{
continue
}
s private=$g(^oddDEF(ClassName,"a",key,35))
if private=1{
continue
}
continue:$g(^oddDEF(ClassName,"a",key,11))=""
;B ; ClassName
s ^tmplzw("insertFromQyeryTestpara",$j,$g(^oddDEF(ClassName,"a",key,11)))=$g(^oddDEF(ClassName,"a",key,47))
}
}
s parakey="",fields=""
f s parakey=$o(^tmplzw("insertFromQyeryTestpara",$j,parakey)) q:parakey="" d
.i fields="" s fields=^tmplzw("insertFromQyeryTestpara",$j,parakey)
.e s fields=fields_","_^tmplzw("insertFromQyeryTestpara",$j,parakey)
;b ; fields
s sd=$zdh(sd,3)
s ed=$zdh(ed,3)
f dd=sd:1:ed d
.s stdate=$zd(dd,3)
.w stdate_"^"_$zt($p($h,",",2)),!
.d ..insertFromQyeryPublic("lizw.CloseCycleData","GetLabTransferDateTime","lizw.User.CloseCycleDateTime","lizw_User.CloseCycleDateTime",stdate,stdate,"","",fields)
q "OK"
}
// W ##CLASS(lizw.CloseCycleData).insertFromQyeryPublic("lizw.CloseCycleData","GetLabTransferDateTime","lizw.User.CloseCycleDateTime","lizw_User.CloseCycleDateTime","2022-01-01","2022-01-01")
ClassMethod insertFromQyeryPublic(queryClass, queryMethod, userName, tableName, arg1 = "", arg2 = "", arg3 = "", arg4 = "", arg5 = "")
{
s totalNum=0
try{
Set queryrset=##class(%ResultSet).%New(queryClass_":"_queryMethod)
do queryrset.Execute(arg1,arg2)
Set columns = queryrset.GetColumnCount()
S SQLresult=##class(%SQL.Statement).%New()
While (queryrset.Next()) {
s values=""
f inum=1:1:columns d
.i values="" s values=""""_queryrset.GetData(inum)_""""
.e s values=values_","_""""_queryrset.GetData(inum)_""""
s sqlStr ="INSERT INTO "_tableName_" ("_fields_") VALUES ("_values_")"
s Status=SQLresult.%Prepare(sqlStr)
s SSRET = SQLresult.%Execute()
; b ; SSRET.%SQLCODE
i SSRET.%SQLCODE'=0 w arg1_"^"_SSRET.%SQLCODE,!
i SSRET.%SQLCODE'=0 b ; SSRET.%SQLCODE
s totalNum=totalNum+1
}
}
catch{
s ^lzw("insertFromQyeryErr",+$h,$zts)=$g(arg1)_"^"_$g(arg2)_"^"_$ze
}
q totalNum
}
二,病案数据、医保结算清单数据等上传,上传数据组织成xml或json等格式,上传数据存表记录。
在实际业务中,经常需要做一些数据上报、第三方接口等等,数据传输格式往往是xml或json等同格式,我们一般会建一个类,Property 就是需要上传的字段,继承%XML.Adaptor, 输出时调用DO Obj.XMLExportToString(.XML,"Response")输出xml。在与第三方交互时,我们往往需要记录给第三方的入参及返回,此时,我们通过%Dictionary.CompiledClass可以很方便的把xml类的数据存储到表。
具体实现:按照接口要求,把注册类和持久类建好,表字段名一致,转换时按名称匹配比较方便,否则要做映射。
优点:把数据上传和合并合到一起了,注册类数据存储到持久类也很方便。如果按正常的步骤,先把数据存起来,再组织xml会比较麻烦一些,特别是上传数据量大,涉及到一堆子表的情况下。
缺点:毕竟多了一步数据存储,会影响效率。如果是走平台或者不需要记录数据就不用这样做。
// 建一个注册类, 转换xml
Class lizw.yb.JSQDXML Extends (%RegisteredObject, %XML.Adaptor)
{
Parameter XMLIGNORENULL = 1;
Parameter XMLIGNOREINVALIDTAG = 1;
Parameter XMLNAME = "Response";
/// 必填
Property EpisodeID As %String(CONTENT = "就诊号", MAXLEN = 200, XMLNAME = "EpisodeID");
/// 人员编号
Property psnno As %String(CONTENT = "人员编号", MAXLEN = 200, XMLNAME = "psn_no");
。
。
。
}
// 建一个持久类, 存储数据
Class lizw.User.JSQDSAVE Extends %Library.Persistent [ ClassType = persistent, Owner = {_SYSTEM}, Not ProcedureBlock, SqlRowIdName = JSQD_rowid, SqlTableName = JSQDSAVE_Data ]
{
Parameter XMLIGNOREINVALIDTAG = 1;
Parameter XMLIGNORENULL = 1;
/// 必填
Property EpisodeID As %String [ SqlColumnNumber = 2, SqlFieldName = JSQD_EpisodeID ];
/// 就诊ID
Property psnno As %String [ SqlColumnNumber = 3, SqlFieldName = psn_no ];
。
。
。
}
/// Return: 出院诊断、手术取病案首页上的 w ##class(lizw.JSQDInsert).GetChargeBillDataGJYB("34430780")
ClassMethod GetChargeBillDataGJYB(AEpisodeID As %String, AIsEMR As %String = "")
{
s ModelObj = ##class(lizw.yb.JSQDXML).%New()
//出院科室
s RMYYCYKS=##Class(EMRservice.HISInterface.PatientInfoAssist).DisDept(AEpisodeID)
s CTLOCDr=$p(RMYYCYKS,"^",1)
s HOSpId=$P(^CTLOC(CTLOCDr),"^",22)
// 取系统参数
s Hospital=""
s ModelObj.EpisodeID=AEpisodeID
s (cykssj,setlid,mdtrtid,adminfo,jjpayStr)="0"
&sql(SELECT max(INPAY_iDate) ,INPAY_djlsh0 , INPAY_zylsh0 ,INPAY_id0000, INPAY_AdmInfoDr, INPAY_Zstr11 INTO :cykssj, :setlid, :mdtrtid,:psnno ,:adminfo, :jjpayStr FROM sqluser.insu_divide WHERE INPAY_AdmDr =:AEpisodeID AND INPAY_Flag ='I' ORDER BY INPAY_Rowid desc)
s ModelObj.psnno=psnno
。
。
。
d ..ObjExchange(ModelObj)
do ModelObj.%Close()
DO ModelObj.XMLExportToString(.XML,"Response")
;b // 输出XML
q XML
}
// 注册 类 数据存储到 表
ClassMethod ObjExchange(ClassOBJ)
{
s ClassName="lizw.yb.JSQDXML"
s dcd1 = ##Class(%Dictionary.CompiledClass).%OpenId(ClassName)
s objName="lizw.User.JSQDSAVE"
s obj=##class(lizw.User.JSQDSAVE).%New()
s cnt=dcd1.Properties.Count()
f i=2:1:cnt d
.s propObj = dcd1.Properties.GetAt(i)
.s PropertyName = propObj.Name
.i ##class(web.DHCBL.BDP.FindTableStructure).PropertyExistOrNot(objName,PropertyName)=1 d
..s $PROPERTY(obj,PropertyName)=$PROPERTY(ClassOBJ,PropertyName)
s $PROPERTY(obj,"supDate")=+$h
d obj.%Save()
s GJYBID=obj.%Id()
s dlen=ClassOBJ.opspdiseinfo.Count()
f diagnum=1:1:dlen d
.s opspdiseinfoobj=##class(lizw.yb.opspdiseinfoSave).%New()
.s opspdiseinfoobj.diagname=ClassOBJ.opspdiseinfo.GetAt(diagnum).diagname
.s opspdiseinfoobj.diagcode=ClassOBJ.opspdiseinfo.GetAt(diagnum).diagcode
.s opspdiseinfoobj.oprnoprtname=ClassOBJ.opspdiseinfo.GetAt(diagnum).oprnoprtname
.s opspdiseinfoobj.oprnoprtcode=ClassOBJ.opspdiseinfo.GetAt(diagnum).oprnoprtcode
.D opspdiseinfoobj.GJYBIDSetObjectId(GJYBID)
.D opspdiseinfoobj.%Save()
。
。
。
}
三,把注册类或者持久类中的数据转换成json。
在实际业务中,对于字段比较多,需要输出成json格式时,我们可以把数据已经组织好的注册类或持久类转换成json键值对。
具体实现:按照字段要求,把存放数据的类建好,字段名跟json要求保持一致,否则要做映射。
优点:把注册类或持久类存放的数据直接转换成json键值,当json涉及的字段较多时,可以省去较多的代码量。
缺点:使用与数据已经组织或已存放好,json键值较多的情况。
/// w ##Class(lizw.JSQDInsert).ReturnInputJSON("2")
ClassMethod ReturnInputJSON(TID As %String) As %String
{
s OutputObj=##class(%DynamicObject).%New()
S obj=##class(lizw.User.JSQDSAVE).%OpenId(TID)
s setlinfoObj=##class(%DynamicObject).%New()
s adm=obj.EpisodeID
s AdmInfoDr=$o(^DHCINADM("0","ADM",adm,""),-1)
s AdmInfo=$g(^DHCINADM(AdmInfoDr))
s InsuAdmCenter=$p(AdmInfo,"^",8)
d OutputObj.%Set("infno","4101A")
s msgid="H42010400158"_$tr($zd(+$h,3),"-")_$tr($zt($p($h,",",2)),":")_$e($tr($zt($p($h,",",2)),":"),1,4)
d OutputObj.%Set("msgid",msgid)
d OutputObj.%Set("insuplc_admdvs",InsuAdmCenter)
d OutputObj.%Set("mdtrtarea_admvs","420100")
。
。
。
d OutputObj.%Set("fixmedins_name","武汉市中西医结合医院(武汉市第一医院)")
d OutputObj.%Set("sign_no","")
s setlinfoarr=..GetDynamicObjectFromOBJ(obj)
s oprninfoArr=##class(%DynamicArray).%New()
S oprninfoId=""
F S oprninfoId=$o(^lizw.yb.oprninfoSaveI("GJYBID",TID,oprninfoId)) Q:oprninfoId="" D
.S obj=##class(lizw.yb.oprninfoSave).%OpenId(oprninfoId)
.s oprninfoObj=..GetDynamicObjectFromOBJ(obj)
.d oprninfoArr.%Push(oprninfoObj)
d setlinfoObj.%Set("oprninfo",oprninfoArr)
s iteminfoArr=##class(%DynamicArray).%New()
S iteminfoId=""
F S iteminfoId=$o(^lizw.yb.bldinfoSaveI("GJYBID",TID,iteminfoId)) Q:iteminfoId="" D
.S obj=##class(lizw.yb.bldinfoSave).%OpenId(iteminfoId)
.s iteminfoObj=..GetDynamicObjectFromOBJ(obj)
.d iteminfoArr.%Push(iteminfoObj)
d setlinfoarr.%Set("bldinfo",iteminfoArr)
s diseinfoArr=##class(%DynamicArray).%New()
S diseinfoId=""
F S diseinfoId=$o(^lizw.yb.diseinfoSaveI("GJYBID",TID,diseinfoId)) Q:diseinfoId="" D
.S obj=##class(lizw.yb.diseinfoSave).%OpenId(diseinfoId)
.s diseinfoObj=..GetDynamicObjectFromOBJ(obj)
.d diseinfoArr.%Push(diseinfoObj)
d setlinfoObj.%Set("diseinfo",diseinfoArr)
s opspdiseinfoArr=##class(%DynamicArray).%New()
S opspdiseinfoId=""
F S opspdiseinfoId=$o(^lizw.yb.opspdiseinfoSaveI("GJYBID",TID,opspdiseinfoId)) Q:opspdiseinfoId="" D
.S obj=##class(lizw.yb.opspdiseinfoSave).%OpenId(opspdiseinfoId)
.s opspdiseinfoObj=..GetDynamicObjectFromOBJ(obj)
.d opspdiseinfoArr.%Push(opspdiseinfoObj)
d setlinfoObj.%Set("opspdiseinfo",opspdiseinfoArr)
s icuinfoArr=##class(%DynamicArray).%New()
S icuinfoId=""
F S icuinfoId=$o(^lizw.yb.icuinfoSaveI("GJYBID",TID,icuinfoId)) Q:icuinfoId="" D
.S obj=##class(lizw.yb.icuinfoSave).%OpenId(icuinfoId)
.s icuinfoObj=..GetDynamicObjectFromOBJ(obj)
.d icuinfoArr.%Push(icuinfoObj)
d setlinfoObj.%Set("icuinfo",icuinfoArr)
d setlinfoObj.%Set("setlinfo",setlinfoarr)
d OutputObj.%Set("input",setlinfoObj)
q TID_$c(0)_OutputObj.%ToJSON()
}
ClassMethod GetDynamicObjectFromOBJ(classOBJ) As %DynamicObject
{
s arr=##class(%DynamicObject).%New()
if (classOBJ.%IsA("%Library.Persistent")||(classOBJ.%IsA("%RegisteredObject"))){
s className=classOBJ.%ClassName()
s pkgName=classOBJ.%PackageName()
s key=""
s:$d(^oddCOM(className)) ClassName=className
s:$d(^oddCOM(pkgName_"."_className)) ClassName=pkgName_"."_className
f {
s key=$o(^oddCOM(ClassName,"a",key))
q:key=""
i $e(key,1)="%"{
continue
}
s private=$g(^oddDEF(ClassName,"a",key,35))
if private=1{
continue
}
continue:((key="GJYBID")||(key="supDate")||(key="BAH")||(key="EpisodeID"))
d arr.%Set(^oddDEF(ClassName,"a",key,47),$PROPERTY(classOBJ,key))
}
}
q arr
}
学习了