在开发业务功能时候经常有需要实现复制功能。这种对应数据库后台就是拷贝数据,以前我还傻乎乎的一个个属性从老对象复制给新对象,如果一个表有80属性,就写80行赋值,扩表了再加。
其中拷贝数据又有两个情况:
1.从一份数据往一个不存在的数据拷贝
2.从一个数据拷贝更新另一个数据
对于全新拷贝数据可以借助M的对象保存的方法%ConstructClone实现,如下:
Class OTH.TestClone Extends %RegisteredObject
{
/// w ##Class(OTH.TestClone).CloneSave()
ClassMethod CloneSave()
{
s objSave=##Class(dbo.Test).%OpenId(1)
//s objSave.Code="1"
//s objSave.CName="1"
//s ret=objSave.%Save()
s objClone=objSave.%ConstructClone()
s objClone.RowID=""
s ret=objClone.%Save()
zw ret
q ""
}
}
测试的Test表
Class dbo.Test Extends %Persistent [ ClassType = persistent, DdlAllowed, Owner = {UnknownUser}, ProcedureBlock, SqlRowIdPrivate, SqlTableName = Test ]
{
/// DDL Primary Key Specification
Index PKTEST On RowID [ PrimaryKey, SqlName = PK_TEST, Type = index, Unique ];
/// 主键
Property RowID As %Library.Integer(MAXVAL = 2147483647, MINVAL = -2147483648) [ Identity, SqlColumnNumber = 2 ];
/// 代码
Property Code As %Library.String(MAXLEN = 10) [ Required, SqlColumnNumber = 3 ];
/// 名称
Property CName As %Library.String(MAXLEN = 128) [ SqlColumnNumber = 4 ];
Storage Default
{
<Data name="TestDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Code</Value>
</Value>
<Value name="3">
<Value>CName</Value>
</Value>
</Data>
<DataLocation>^dbo.TestD</DataLocation>
<DefaultData>TestDefaultData</DefaultData>
<IdLocation>^dbo.TestD</IdLocation>
<IndexLocation>^dbo.TestI</IndexLocation>
<StreamLocation>^dbo.TestS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}
}
全新拷贝很好说,拷贝结构OK,今天主要说第二种情况。比如我遇到的功能就是复制粘贴菌结果。这时候是把一个RowID的数据和他子表数据拷贝到另一个RowID的数据和他子表。这时候借助%ConstructClone就会报错,报RowID不可修改。
如下是会报错的,报RowID不可修改
Class OTH.TestClone Extends %RegisteredObject
{
/// w ##Class(OTH.TestClone).CloneSave()
ClassMethod CloneSave()
{
//把1的属性值拷贝到2里面
s objSave=##Class(dbo.Test).%OpenId(1)
s objClone=objSave.%ConstructClone()
s objClone.RowID=2
s ret=objClone.%Save()
zw ret
q ""
}
}
报错如下:

为此实现自己的拷贝属性方法
/// 拷贝相同表的两个对象属性
/// w ##Class(LIS.WS.DHCLISServiceBase).CopyTableRow()
/// SourceObj:源对象
/// PerObj:目标对象
/// NoCopyList:不复制列名列表 s NoCopyMap=$lb("aa","bb")
ClassMethod CopyTableRow(SourceObj, PerObj, NoCopyList)
{
s SourceObj=$g(SourceObj)
s PerObj=$g(PerObj)
s NoCopyList=$g(NoCopyList)
s NoCopyMap=""
i $l(NoCopyList) d
.f i=1:1:$ll(NoCopyList) d
..s NoCopyMap($lg(NoCopyList,i))=""
s TableName=$CLASSNAME(SourceObj)
s rset = ##class(%ResultSet).%New()
d rset.Prepare("select COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='dbo' AND REPLACE(TABLE_NAME,'_','')='"_$REPLACE(TableName,"dbo.","")_"' Order by ORDINAL_POSITION")
s exeret=rset.Execute()
While(rset.Next())
{
s colField=rset.GetColumnName(1)
s ColValue=rset.GetDataByName(colField)
i (ColValue'="RowID")&&('$d(NoCopyMap(ColValue))) d
.s exeStr="(SourceObj,PerObj) s PerObj."_ColValue_"=SourceObj."_ColValue
.x (exeStr,.SourceObj,.PerObj)
}
q 1
}
这样多表拷贝就变成如下代码实现了
借助了托管事务保证事务性,托管事务参照托管事务
和托管事务使用
/// 拷贝结果
/// w ##Class(IDP.WS.BLL.DHCIDPResult).CopyOrgResMTHD("6281","6295","","","","","","","","","","","","","")
/// SourceResDR:源报告结果主键
/// PerResDR:目标报告结果主键
ClassMethod CopyOrgResMTHD(SourceResDR, PerResDR, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, Sessions, Output RowCount As %String) As %String
{
s SourceResDR=$g(SourceResDR)
s PerResDR=$g(PerResDR)
//托管事务拷贝菌结果
q ##Class(LIS.WS.DHCLISServiceBase).DeclarativeTrans("IDP.WS.BLL.DHCIDPResult","CopyOrgResDo",SourceResDR, PerResDR, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, Sessions)
}
/// 拷贝结果执行
/// w ##Class(IDP.WS.BLL.DHCIDPResult).CopyOrgResMTHD(15,"","","","","","","","","","","","","","")
/// SourceResDR:源报告结果主键
/// PerResDR:目标报告结果主键
ClassMethod CopyOrgResDo(SourceResDR, PerResDR, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, Sessions, Output RowCount As %String) As %String
{
s SourceResDR=$g(SourceResDR)
s PerResDR=$g(PerResDR)
s PerReportDR=$lg($g(^dbo.RPVisitNumberReportResultD(PerResDR)),2)
s PerReportStatus=$lg($g(^dbo.RPVisitNumberReportD(PerReportDR)),22)
i PerReportStatus="30" s PerReportStatus="3"
i PerReportStatus="3" q "-1^目标报告已经审核,不允许粘贴结果!"
s SourceRes=##Class(dbo.RPVisitNumberReportResult).%OpenId(SourceResDR)
s PerRes=##Class(dbo.RPVisitNumberReportResult).%OpenId(PerResDR)
//不拷贝的列,RowID默认不拷贝
s NoCopyList=$lb("VisitNumberReportDR","RPVisitNumberTestSetDR","TestCodeDR")
d ##Class(LIS.WS.DHCLISServiceBase).CopyTableRow(SourceRes,PerRes,NoCopyList)
s sc=PerRes.%Save()
i ('$SYSTEM.Status.IsOK(sc)) d
.THROW ##class(%Exception.SystemException).%New("事务委托","D",,"-1^更新报告结果失败:"_$SYSTEM.Status.GetErrorText(sc))
//遍历拷贝药敏
s AntibioticsDR="" f s AntibioticsDR=$o(^dbo.RPVisitNumberReportResSenI("IndexAntibiocs",SourceResDR,AntibioticsDR)) q:AntibioticsDR="" d
.s SenDR="" f s SenDR=$o(^dbo.RPVisitNumberReportResSenI("IndexAntibiocs",SourceResDR,AntibioticsDR,SenDR)) q:SenDR="" d
..s PerSenDR=""
..i $d(^dbo.RPVisitNumberReportResSenI("IndexAntibiocs",PerResDR,AntibioticsDR)) d
...s PerSenDR=$o(^dbo.RPVisitNumberReportResSenI("IndexAntibiocs",PerResDR,AntibioticsDR,""))
..s SourceSen=##Class(dbo.RPVisitNumberReportResSen).%OpenId(SenDR)
..i '$l(PerSenDR) s NewSenObj=##Class(dbo.RPVisitNumberReportResSen).%New()
..e s NewSenObj=##Class(dbo.RPVisitNumberReportResSen).%OpenId(PerSenDR)
..d ##Class(LIS.WS.DHCLISServiceBase).CopyTableRow(SourceSen,NewSenObj)
..s NewSenObj.VisitNumberReportResultDR=PerRes.RowID
..s sc=NewSenObj.%Save()
..i ('$SYSTEM.Status.IsOK(sc)) d
...THROW ##class(%Exception.SystemException).%New("事务委托","D",,"-1^更新药敏结果失败:"_$SYSTEM.Status.GetErrorText(sc))
//遍历拷贝耐药机制
s ResistanceItemDR="" f s ResistanceItemDR=$o(^dbo.RPVisitNumberRepResRstI("IndexDataMaster",SourceResDR,ResistanceItemDR)) q:ResistanceItemDR="" d
.s RstDR="" f s RstDR=$o(^dbo.RPVisitNumberRepResRstI("IndexDataMaster",SourceResDR,ResistanceItemDR,RstDR)) q:RstDR="" d
..s PerRstDR=""
..i $d(^dbo.RPVisitNumberRepResRstI("IndexDataMaster",PerResDR,ResistanceItemDR)) d
...s PerRstDR=$o(^dbo.RPVisitNumberRepResRstI("IndexDataMaster",PerResDR,ResistanceItemDR,""))
..s SourceRst=##Class(dbo.RPVisitNumberRepResRst).%OpenId(RstDR)
..i '$l(PerRstDR) s NewRstObj=##Class(dbo.RPVisitNumberRepResRst).%New()
..e s NewRstObj=##Class(dbo.RPVisitNumberRepResRst).%OpenId(PerRstDR)
..d ##Class(LIS.WS.DHCLISServiceBase).CopyTableRow(SourceRst,NewRstObj)
..s NewRstObj.VisitNumberReportResultDR=PerRes.RowID
..s sc=NewRstObj.%Save()
..i ('$SYSTEM.Status.IsOK(sc)) d
...THROW ##class(%Exception.SystemException).%New("事务委托","D",,"-1^更新耐药机制结果失败:"_$SYSTEM.Status.GetErrorText(sc))
q ""
}
借助%ConstructClone和自己封装的拷贝方法从而优雅的实现复制粘贴功能