// TODO: 是否检查流通信息,需要可以通过参数控制 // 检索书目记录下属的事项记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle return_record_xml 要在DeleteEntityInfo结构中返回OldRecord内容 // check_circulation_info 检查是否具有流通信息。如果具有则会报错 2012/12/19 把缺省行为变为此参数 // return: // -1 error // 0 not exist item dbname // 1 exist item dbname public int SearchChildItems(RmsChannel channel, string strBiblioRecPath, string strStyle, out long lHitCount, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; lHitCount = 0; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); bool bCheckCirculationInfo = StringUtil.IsInList("check_circulation_info", strStyle); bool bOnlyGetCount = StringUtil.IsInList("only_getcount", strStyle); string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath); string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath); // 获得书目库对应的事项库名 string strItemDbName = ""; nRet = this.GetItemDbName(strBiblioDbName, out strItemDbName, out strError); if (nRet == -1) goto ERROR1; if (String.IsNullOrEmpty(strItemDbName) == true) return 0; // 检索实体库中全部从属于特定id的记录 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录") + "'><item><word>" + strBiblioRecId + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; long lRet = channel.DoSearch(strQueryXml, "entities", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "没有找到属于书目记录 '" + strBiblioRecPath + "' 的任何"+this.ItemName+"记录"; return 0; } lHitCount = lRet; // 仅返回命中条数 if (bOnlyGetCount == true) return 0; int nResultCount = (int)lRet; int nMaxCount = 10000; if (nResultCount > nMaxCount) { strError = "命中"+this.ItemName+"记录数 " + nResultCount.ToString() + " 超过 "+nMaxCount.ToString()+", 暂时不支持针对它们的删除操作"; goto ERROR1; } int nStart = 0; int nPerCount = 100; for (; ; ) { List<string> aPath = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "aPath.Count == 0"; goto ERROR1; } // 获得每条记录 for (int i = 0; i < aPath.Count; i++) { string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; lRet = channel.GetRes(aPath[i], out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (lRet == -1) { /* entityinfo.RecPath = aPath[i]; entityinfo.ErrorCode = channel.OriginErrorCode; entityinfo.ErrorInfo = channel.ErrorInfo; entityinfo.OldRecord = ""; entityinfo.OldTimestamp = null; entityinfo.NewRecord = ""; entityinfo.NewTimestamp = null; entityinfo.Action = ""; * */ if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "获取"+this.ItemName+"记录 '" + aPath[i] + "' 时发生错误: " + strError; goto ERROR1; // goto CONTINUE; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; if (bCheckCirculationInfo == true) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = this.ItemName + "记录 '" + aPath[i] + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } /* entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); * */ // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 nRet = this.HasCirculationInfo(domExist, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError = "拟删除的" + this.ItemName + "记录 '" + entityinfo.RecPath + "' 中" + strError + "(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } } // CONTINUE: entityinfos.Add(entityinfo); } nStart += aPath.Count; if (nStart >= nResultCount) break; } return 1; ERROR1: return -1; }
// TODO: 是否检查流通信息,需要可以通过参数控制 // 检索书目记录下属的事项记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle return_record_xml 要在DeleteEntityInfo结构中返回OldRecord内容 // check_circulation_info 检查是否具有流通信息。如果具有则会报错 2012/12/19 把缺省行为变为此参数 // 当包含 limit: 时,定义最多取得记录的个数。例如希望最多取得 10 条,可以定义 limit:10 // return: // -1 error // 0 not exist item dbname // 1 exist item dbname public int SearchChildItems(RmsChannel channel, string strBiblioRecPath, string strStyle, DigitalPlatform.LibraryServer.LibraryApplication.Delegate_checkRecord procCheckRecord, object param, out long lHitCount, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; lHitCount = 0; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); bool bCheckCirculationInfo = StringUtil.IsInList("check_circulation_info", strStyle); bool bOnlyGetCount = StringUtil.IsInList("only_getcount", strStyle); string strLimit = StringUtil.GetParameterByPrefix(strStyle, "limit", ":"); string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath); string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath); // 获得书目库对应的事项库名 string strItemDbName = ""; nRet = this.GetItemDbName(strBiblioDbName, out strItemDbName, out strError); if (nRet == -1) goto ERROR1; if (String.IsNullOrEmpty(strItemDbName) == true) return 0; // 检索实体库中全部从属于特定id的记录 string strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录") + "'><item><word>" + strBiblioRecId + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; long lRet = channel.DoSearch(strQueryXml, "entities", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "没有找到属于书目记录 '" + strBiblioRecPath + "' 的任何" + this.ItemName + "记录"; return 0; } lHitCount = lRet; // 仅返回命中条数 if (bOnlyGetCount == true) return 0; int nResultCount = (int)lRet; int nMaxCount = 10000; if (nResultCount > nMaxCount) { strError = "命中" + this.ItemName + "记录数 " + nResultCount.ToString() + " 超过 " + nMaxCount.ToString() + ", 暂时不支持针对它们的删除操作"; goto ERROR1; } string strColumnStyle = "id,xml,timestamp"; int nLimit = -1; if (string.IsNullOrEmpty(strLimit) == false) Int32.TryParse(strLimit, out nLimit); int nStart = 0; int nPerCount = 100; if (nLimit != -1 && nPerCount > nLimit) nPerCount = nLimit; for (; ; ) { #if NO List<string> aPath = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "aPath.Count == 0"; goto ERROR1; } #endif Record[] searchresults = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, strColumnStyle, "zh", null, out searchresults, out strError); if (lRet == -1) goto ERROR1; if (searchresults == null) { strError = "searchresults == null"; goto ERROR1; } if (searchresults.Length == 0) { strError = "searchresults.Length == 0"; goto ERROR1; } // 获得每条记录 // for (int i = 0; i < aPath.Count; i++) int i = 0; foreach (Record record in searchresults) { string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (record.RecordBody == null || string.IsNullOrEmpty(record.RecordBody.Xml) == true) { // TODO: 这里需要改造为直接从结果集中获取 xml,timestamp lRet = channel.GetRes(record.Path, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "获取" + this.ItemName + "记录 '" + record.Path + "' 时发生错误: " + strError; goto ERROR1; // goto CONTINUE; } } else { strXml = record.RecordBody.Xml; strOutputPath = record.Path; timestamp = record.RecordBody.Timestamp; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; if (bCheckCirculationInfo == true || procCheckRecord != null) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = this.ItemName + "记录 '" + record.Path + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } // 2016/11/15 if (procCheckRecord != null) { nRet = procCheckRecord( nStart + i, strOutputPath, domExist, timestamp, param, out strError); if (nRet != 0) return nRet; } /* entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); * */ // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 // return: // -1 出错 // 0 没有 // 1 有。报错信息在strError中 nRet = this.HasCirculationInfo(domExist, out strError); if (nRet == -1) goto ERROR1; if (nRet == 1) { strError = "拟删除的" + this.ItemName + "记录 '" + entityinfo.RecPath + "' 中" + strError + "(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } } // CONTINUE: entityinfos.Add(entityinfo); i++; } nStart += searchresults.Length; if (nStart >= nResultCount) break; if (nLimit != -1 && nStart >= nLimit) break; } return 1; ERROR1: return -1; }
// 获得书目记录下属的实体记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle return_record_xml // return: // -1 error // 0 succeed public int SearchChildRecords(RmsChannel channel, List<string> aPath, string strStyle, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); // 获得每条记录 for (int i = 0; i < aPath.Count; i++) { string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; long lRet = channel.GetRes(aPath[i], out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 是否报错? strError = "获取下级记录 '" + aPath[i] + "' 时发生错误: " + strError; goto ERROR1; // goto CONTINUE; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; #if NO if (bCheckBorrowInfo == true || bCountBorrowInfo == true) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = "实体记录 '" + aPath[i] + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 string strDetail = ""; bool bHasCirculationInfo = IsEntityHasCirculationInfo(domExist, out strDetail); if (bHasCirculationInfo == true) { if (bCheckBorrowInfo == true) { strError = "拟删除的册记录 '" + entityinfo.RecPath + "' 中包含有流通信息(" + strDetail + ")(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } if (bCountBorrowInfo == true) nBorrowInfoCount++; } } #endif // CONTINUE: entityinfos.Add(entityinfo); } return 0; ERROR1: return -1; }
// 源记录不存在,应该忽略;目标库不存在,也应该忽略 /* <copyEntityRecords> 被复制的实体记录(容器)。只有当<action>为*copy*时才有这个元素。 <record recPath='中文图书实体/100' targetRecPath='中文图书实体/110'>...</record> 这个元素可以重复。注意元素内文本内容目前为空。recPath属性为源记录路径,targetRecPath为目标记录路径 ... </copyEntityRecords> <moveEntityRecords> 被移动的实体记录(容器)。只有当<action>为*move*时才有这个元素。 <record recPath='中文图书实体/100' targetRecPath='中文图书实体/110'>...</record> 这个元素可以重复。注意元素内文本内容目前为空。recPath属性为源记录路径,targetRecPath为目标记录路径 ... </moveEntityRecords> * */ public int CopySubRecords( RmsChannel channel, XmlNode node, string strTargetBiblioRecPath, out string strError) { strError = ""; string strAction = ""; if (StringUtil.HasHead(node.Name, "copy") == true) strAction = "copy"; else if (StringUtil.HasHead(node.Name, "move") == true) // 2011/12/5 原先有BUG "copy" strAction = "move"; else { strError = "不能识别的元素名 '" + node.Name + "'"; return -1; } XmlNodeList nodes = node.SelectNodes("record"); foreach (XmlNode record_node in nodes) { string strSourceRecPath = DomUtil.GetAttr(record_node, "recPath"); string strTargetRecPath = DomUtil.GetAttr(record_node, "targetRecPath"); string strNewBarcode = DomUtil.GetAttr(record_node, "newBarcode"); string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; long lRet = channel.GetRes(strSourceRecPath, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; // 是否报错? strError = "获取下级记录 '" + strSourceRecPath + "' 时发生错误: " + strError; return -1; // goto CONTINUE; } DeleteEntityInfo entityinfo = new DeleteEntityInfo(); entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; entityinfo.OldRecord = strXml; List<DeleteEntityInfo> entityinfos = new List<DeleteEntityInfo>(); entityinfos.Add(entityinfo); // TODO: 如果目标数据库已经不存在,要跳过 List<string> target_recpaths = new List<string>(); target_recpaths.Add(strTargetRecPath); List<string> newbarcodes = new List<string>(); newbarcodes.Add(strNewBarcode); // 复制属于同一书目记录的全部实体记录 // parameters: // strAction copy / move // return: // -1 error // >=0 实际复制或者移动的实体记录数 int nRet = CopyBiblioChildRecords(channel, strAction, entityinfos, target_recpaths, strTargetBiblioRecPath, newbarcodes, out strError); if (nRet == -1) return -1; } return 0; }
// 2016/11/15 改造为不用 GetRes() 获取记录 // 检索书目记录下属的实体记录,返回少量必要的信息,可以提供后面实做删除时使用 // parameters: // strStyle check_borrow_info,count_borrow_info,return_record_xml // 当包含 check_borrow_info 时,发现第一个流通信息,本函数就立即返回-1 // 当包含 count_borrow_info 时,函数要统计全部流通信息的个数 // 当包含 libraryCodes: 时,表示仅获得所列分馆代码的册记录。注意多个馆代码之间用竖线分隔 // 当包含 limit: 时,定义最多取得记录的个数。例如希望最多取得 10 条,可以定义 limit:10 // return: // -2 not exist entity dbname // -1 error // >=0 含有流通信息的实体记录个数, 当strStyle包含count_borrow_info时。 public int SearchChildEntities(RmsChannel channel, string strBiblioRecPath, string strStyle, Delegate_checkRecord procCheckRecord, object param, out long lHitCount, out List<DeleteEntityInfo> entityinfos, out string strError) { strError = ""; lHitCount = 0; entityinfos = new List<DeleteEntityInfo>(); int nRet = 0; bool bCheckBorrowInfo = StringUtil.IsInList("check_borrow_info", strStyle); bool bCountBorrowInfo = StringUtil.IsInList("count_borrow_info", strStyle); bool bReturnRecordXml = StringUtil.IsInList("return_record_xml", strStyle); bool bOnlyGetCount = StringUtil.IsInList("only_getcount", strStyle); if (bCheckBorrowInfo == true && bCountBorrowInfo == true) { strError = "strStyle中check_borrow_info和count_borrow_info不能同时具备"; return -1; } string strLibraryCodeParam = StringUtil.GetParameterByPrefix(strStyle, "libraryCodes", ":"); string strLimit = StringUtil.GetParameterByPrefix(strStyle, "limit", ":"); string strBiblioDbName = ResPath.GetDbName(strBiblioRecPath); string strBiblioRecId = ResPath.GetRecordId(strBiblioRecPath); // 获得书目库对应的实体库名 string strItemDbName = ""; nRet = this.GetItemDbName(strBiblioDbName, out strItemDbName, out strError); if (nRet == -1) goto ERROR1; // 2008/12/5 if (String.IsNullOrEmpty(strItemDbName) == true) return 0; // 检索实体库中全部从属于特定id的记录 string strQueryXml = ""; if (string.IsNullOrEmpty(strLibraryCodeParam) == true) { strQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录") // 2007/9/14 + "'><item><word>" + strBiblioRecId + "</word><match>exact</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; } else { // 仅仅取得当前用户管辖的分馆的册记录 List<string> codes = StringUtil.SplitList(strLibraryCodeParam, '|'); // sessioninfo.LibraryCodeList foreach (string strCode in codes) { string strOneQueryXml = "<target list='" + StringUtil.GetXmlStringSimple(strItemDbName + ":" + "父记录+馆藏地点") + "'><item><word>" + StringUtil.GetXmlStringSimple(strBiblioRecId + "|" + strCode + "/") + "</word><match>left</match><relation>=</relation><dataType>string</dataType><maxCount>-1</maxCount></item><lang>" + "zh" + "</lang></target>"; if (string.IsNullOrEmpty(strQueryXml) == false) { Debug.Assert(String.IsNullOrEmpty(strQueryXml) == false, ""); strQueryXml += "<operator value='OR'/>"; } strQueryXml += strOneQueryXml; } if (codes.Count > 0) { strQueryXml = "<group>" + strQueryXml + "</group>"; } } long lRet = channel.DoSearch(strQueryXml, "entities", "", // strOuputStyle out strError); if (lRet == -1) goto ERROR1; if (lRet == 0) { strError = "没有找到属于书目记录 '" + strBiblioRecPath + "' 的任何实体记录"; return 0; } lHitCount = lRet; // 仅返回命中条数 if (bOnlyGetCount == true) return 0; int nResultCount = (int)lRet; if (nResultCount > 10000) { strError = "命中册记录数 " + nResultCount.ToString() + " 超过 10000, 暂时不支持针对它们的删除操作"; goto ERROR1; } string strColumnStyle = "id,xml,timestamp"; int nLimit = -1; if (string.IsNullOrEmpty(strLimit) == false) Int32.TryParse(strLimit, out nLimit); int nBorrowInfoCount = 0; int nStart = 0; int nPerCount = 100; if (nLimit != -1 && nPerCount > nLimit) nPerCount = nLimit; for (; ; ) { #if NO List<string> aPath = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, "zh", null, out aPath, out strError); if (lRet == -1) goto ERROR1; if (aPath.Count == 0) { strError = "aPath.Count == 0"; goto ERROR1; } #endif Record[] searchresults = null; lRet = channel.DoGetSearchResult( "entities", nStart, nPerCount, strColumnStyle, "zh", null, out searchresults, out strError); if (lRet == -1) goto ERROR1; if (searchresults == null) { strError = "searchresults == null"; goto ERROR1; } if (searchresults.Length == 0) { strError = "searchresults.Length == 0"; goto ERROR1; } // 获得每条记录 // for (int i = 0; i < aPath.Count; i++) int i = 0; foreach (Record record in searchresults) { // EntityInfo info = new EntityInfo(); // info.OldRecPath = record.Path; string strMetaData = ""; string strXml = ""; byte[] timestamp = null; string strOutputPath = ""; DeleteEntityInfo entityinfo = new DeleteEntityInfo(); if (record.RecordBody == null || string.IsNullOrEmpty(record.RecordBody.Xml) == true) { lRet = channel.GetRes(record.Path, out strXml, out strMetaData, out timestamp, out strOutputPath, out strError); if (lRet == -1) { if (channel.ErrorCode == ChannelErrorCode.NotFound) continue; strError = "获取实体记录 '" + record.Path + "' 时发生错误: " + strError; goto ERROR1; } } else { strXml = record.RecordBody.Xml; strOutputPath = record.Path; timestamp = record.RecordBody.Timestamp; } entityinfo.RecPath = strOutputPath; entityinfo.OldTimestamp = timestamp; if (bReturnRecordXml == true) entityinfo.OldRecord = strXml; if (bCheckBorrowInfo == true || bCountBorrowInfo == true || procCheckRecord != null) { // 检查是否有借阅信息 // 把记录装入DOM XmlDocument domExist = new XmlDocument(); try { domExist.LoadXml(strXml); } catch (Exception ex) { strError = "实体记录 '" + strOutputPath + "' 装载进入DOM时发生错误: " + ex.Message; goto ERROR1; } if (procCheckRecord != null) { nRet = procCheckRecord( nStart + i, strOutputPath, domExist, timestamp, param, out strError); if (nRet != 0) return nRet; } entityinfo.ItemBarcode = DomUtil.GetElementText(domExist.DocumentElement, "barcode"); // TODO: 在日志恢复阶段调用本函数时,是否还有必要检查是否具有流通信息?似乎这时应强制删除为好 // 观察已经存在的记录是否有流通信息 string strDetail = ""; bool bHasCirculationInfo = IsEntityHasCirculationInfo(domExist, out strDetail); if (bHasCirculationInfo == true) { if (bCheckBorrowInfo == true) { strError = "拟删除的册记录 '" + entityinfo.RecPath + "' 中包含有流通信息(" + strDetail + ")(此种情况可能不限于这一条),不能删除。因此全部删除操作均被放弃。"; goto ERROR1; } if (bCountBorrowInfo == true) nBorrowInfoCount++; } } // CONTINUE: entityinfos.Add(entityinfo); i++; } nStart += searchresults.Length; if (nStart >= nResultCount) break; if (nLimit != -1 && nStart >= nLimit) break; } return nBorrowInfoCount; ERROR1: return -1; }