Exemplo n.º 1
0
        static NormalResult Set(PatronItem patron,
                                Record record,
                                DateTime lastWriteTime)
        {
            XmlDocument dom = new XmlDocument();

            try
            {
                dom.LoadXml(record.RecordBody.Xml);
            }
            catch (Exception ex)
            {
                return(new NormalResult
                {
                    Value = -1,
                    ErrorInfo = $"读者记录装载进入 XMLDOM 时出错:{ex.Message}",
                    ErrorCode = "loadXmlError"
                });
            }

            // TODO: 如果 XML 记录尺寸太大,可以考虑删除一些无关紧要的元素以后进入 patron.Xml,避免溢出 SQLite 一条记录可以存储的最大尺寸

            string pii = DomUtil.GetElementText(dom.DocumentElement, "barcode");

            if (string.IsNullOrEmpty(pii))
            {
                pii = "@refID:" + DomUtil.GetElementText(dom.DocumentElement, "refID");
            }

            string cardNumber = DomUtil.GetElementText(dom.DocumentElement, "cardNumber");

            cardNumber = cardNumber.ToUpper();
            if (string.IsNullOrEmpty(cardNumber) == false)
            {
                cardNumber = "," + cardNumber + ",";
            }

            patron.PII           = pii;
            patron.RecPath       = record.Path;
            patron.Bindings      = cardNumber;
            patron.Xml           = record.RecordBody.Xml;
            patron.Timestamp     = record.RecordBody.Timestamp;
            patron.LastWriteTime = lastWriteTime;
            return(new NormalResult());
        }
Exemplo n.º 2
0
        // 第一阶段:获得全部读者库记录,进入本地数据库
        // result.Value
        //      -1  出错
        //      >=0 实际获得的读者记录条数
        public static async Task <ReplicationPlan> DownloadAllPatronRecordAsync(CancellationToken token)
        {
            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromMinutes(5);  // 设置 5 分钟。因为读者记录检索需要一定时间
            try
            {
                ReplicationPlan plan = GetReplicationPlan(channel);
                if (plan.Value == -1)
                {
                    return(plan);
                }


                int nRedoCount = 0;
REDO:
                if (token.IsCancellationRequested)
                {
                    return new ReplicationPlan
                           {
                               Value     = -1,
                               ErrorInfo = "用户中断"
                           }
                }
                ;
                // 检索全部读者库记录
                long lRet = channel.SearchReader(null,  // stop,
                                                 "<all>",
                                                 "",
                                                 -1,
                                                 "__id",
                                                 "left",
                                                 "zh",
                                                 null, // strResultSetName
                                                 "",   // strOutputStyle
                                                 out string strError);
                if (lRet == -1)
                {
                    // 一次重试机会
                    if (lRet == -1 &&
                        (channel.ErrorCode == ErrorCode.RequestCanceled || channel.ErrorCode == ErrorCode.RequestError) &&
                        nRedoCount < 2)
                    {
                        nRedoCount++;
                        goto REDO;
                    }

                    return(new ReplicationPlan
                    {
                        Value = -1,
                        ErrorInfo = strError,
                        ErrorCode = channel.ErrorCode.ToString()
                    });
                }

                long hitcount = lRet;

                // 把超时时间改短一点
                channel.Timeout = TimeSpan.FromSeconds(20);

                DateTime search_time = DateTime.Now;

                // 获取和存储记录
                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             null,
                                                             $"id,xml,timestamp",
                                                             "zh");
                using (BiblioCacheContext context = new BiblioCacheContext())
                {
                    context.Database.EnsureCreated();

                    // 删除 Patrons 里面的已有记录
                    context.Patrons.RemoveRange(context.Patrons.ToList());
                    await context.SaveChangesAsync(token);

                    // loader.Prompt += this.Loader_Prompt;
                    if (hitcount > 0)
                    {
                        int i = 0;
                        foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                        {
                            if (token.IsCancellationRequested)
                            {
                                return new ReplicationPlan
                                       {
                                           Value     = -1,
                                           ErrorInfo = "用户中断"
                                       }
                            }
                            ;

                            PatronItem item = new PatronItem();

                            var result = Set(item, record, search_time);
                            if (result.Value == -1)
                            {
                                // TODO: 是否汇总报错信息?
                                continue;
                            }
                            context.Patrons.Add(item);

                            if ((i % 10) == 0)
                            {
                                await context.SaveChangesAsync(token);
                            }

                            i++;
                        }

                        await context.SaveChangesAsync(token);
                    }
                }

                return(new ReplicationPlan
                {
                    Value = (int)hitcount,
                    StartDate = plan.StartDate
                });
            }
            catch (Exception ex)
            {
                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorInfo = $"DownloadAllPatronRecord() 出现异常:{ex.Message}"
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);
            }
        }
Exemplo n.º 3
0
        static NormalResult Set(PatronItem patron,
                                Record record,
                                DateTime lastWriteTime)
        {
            XmlDocument dom = new XmlDocument();

            try
            {
                dom.LoadXml(record.RecordBody.Xml);
            }
            catch (Exception ex)
            {
                return(new NormalResult
                {
                    Value = -1,
                    ErrorInfo = $"读者记录装载进入 XMLDOM 时出错:{ex.Message}",
                    ErrorCode = "loadXmlError"
                });
            }

            // TODO: 如果 XML 记录尺寸太大,可以考虑删除一些无关紧要的元素以后进入 patron.Xml,避免溢出 SQLite 一条记录可以存储的最大尺寸

            string pii = DomUtil.GetElementText(dom.DocumentElement, "barcode");

            if (string.IsNullOrEmpty(pii))
            {
                pii = "@refID:" + DomUtil.GetElementText(dom.DocumentElement, "refID");
            }

            string cardNumber = DomUtil.GetElementText(dom.DocumentElement, "cardNumber");

            cardNumber = cardNumber.ToUpper();
            if (string.IsNullOrEmpty(cardNumber) == false)
            {
                cardNumber = "," + cardNumber + ",";
            }

            // 2020/7/17
            if (pii.StartsWith("@") == false)
            {
                string libraryCode = DomUtil.GetElementText(dom.DocumentElement, "libraryCode");
                var    ret         = ShelfData.GetOwnerInstitution(libraryCode + "/", out string isil, out string alternative);
                if (ret == true)
                {
                    // 应该是 xxx.xxx 形态
                    if (string.IsNullOrEmpty(isil) == false)
                    {
                        pii = isil + "." + pii;
                    }
                    else if (string.IsNullOrEmpty(alternative) == false)
                    {
                        pii = alternative + "." + pii;
                    }
                }
            }

            patron.PII           = pii;
            patron.RecPath       = record.Path;
            patron.Bindings      = cardNumber;
            patron.Xml           = record.RecordBody.Xml;
            patron.Timestamp     = record.RecordBody.Timestamp;
            patron.LastWriteTime = lastWriteTime;
            return(new NormalResult());
        }
Exemplo n.º 4
0
        // 第一阶段:获得全部读者库记录,进入本地数据库
        // result.Value
        //      -1  出错
        //      >=0 实际获得的读者记录条数
        public static async Task <ReplicationPlan> DownloadAllPatronRecordAsync(
            Delegate_writeLog writeLog,
            CancellationToken token)
        {
            _inDownloadingPatron++;

            // 2020/9/26
            if (_inDownloadingPatron > 1)
            {
                _inDownloadingPatron--;
                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorCode = "running",
                    ErrorInfo = "前一次的“下载全部读者记录到本地缓存”过程还在进行中,本次触发被放弃"
                });
            }

            writeLog?.Invoke($"开始下载全部读者记录到本地缓存");
            LibraryChannel channel     = App.CurrentApp.GetChannel();
            var            old_timeout = channel.Timeout;

            channel.Timeout = TimeSpan.FromMinutes(5);  // 设置 5 分钟。因为读者记录检索需要一定时间
            try
            {
                ReplicationPlan plan = GetReplicationPlan(channel);

                writeLog?.Invoke($"GetReplicationPlan() return {plan.ToString()}");

                if (plan.Value == -1)
                {
                    return(plan);
                }

                int nRedoCount = 0;
REDO:
                if (token.IsCancellationRequested)
                {
                    return new ReplicationPlan
                           {
                               Value     = -1,
                               ErrorInfo = "用户中断"
                           }
                }
                ;
                // 检索全部读者库记录
                long lRet = channel.SearchReader(null,  // stop,
                                                 "<all>",
                                                 "",
                                                 -1,
                                                 "__id",
                                                 "left",
                                                 "zh",
                                                 null, // strResultSetName
                                                 "",   // strOutputStyle
                                                 out string strError);
                if (lRet == -1)
                {
                    writeLog?.Invoke($"SearchReader() 出错, strError={strError}, channel.ErrorCode={channel.ErrorCode}");

                    // 一次重试机会
                    if (lRet == -1 &&
                        (channel.ErrorCode == ErrorCode.RequestCanceled || channel.ErrorCode == ErrorCode.RequestError) &&
                        nRedoCount < 2)
                    {
                        nRedoCount++;
                        goto REDO;
                    }

                    return(new ReplicationPlan
                    {
                        Value = -1,
                        ErrorInfo = strError,
                        ErrorCode = channel.ErrorCode.ToString()
                    });
                }

                long hitcount = lRet;

                writeLog?.Invoke($"共检索命中读者记录 {hitcount} 条");

                // 把超时时间改短一点
                channel.Timeout = TimeSpan.FromSeconds(20);

                DateTime search_time = DateTime.Now;

                Hashtable pii_table   = new Hashtable();
                int       skip_count  = 0;
                int       error_count = 0;

                // 获取和存储记录
                ResultSetLoader loader = new ResultSetLoader(channel,
                                                             null,
                                                             null,
                                                             $"id,xml,timestamp",
                                                             "zh");
                using (BiblioCacheContext context = new BiblioCacheContext())
                {
                    context.Database.EnsureCreated();

                    // 删除 Patrons 里面的已有记录
                    context.Patrons.RemoveRange(context.Patrons.ToList());
                    await context.SaveChangesAsync(token);

                    // loader.Prompt += this.Loader_Prompt;
                    if (hitcount > 0)
                    {
                        int i = 0;
                        foreach (DigitalPlatform.LibraryClient.localhost.Record record in loader)
                        {
                            if (token.IsCancellationRequested)
                            {
                                return new ReplicationPlan
                                       {
                                           Value     = -1,
                                           ErrorInfo = "用户中断"
                                       }
                            }
                            ;

                            PatronItem item = new PatronItem();

                            // result.Value:
                            //      -1  出错
                            //      0   需要跳过这条读者记录
                            //      1   成功
                            var result = Set(item, record, search_time);
                            if (result.Value == -1 || result.Value == 0)
                            {
                                // TODO: 是否汇总报错信息?

                                if (result.Value == -1)
                                {
                                    writeLog?.Invoke($"Set() ({item.RecPath}) 出错: {result.ErrorInfo}");
                                    error_count++;
                                }
                                if (result.Value == 0)
                                {
                                    skip_count++;
                                }
                                continue;
                            }

                            //
                            if (pii_table.ContainsKey(result.PII))
                            {
                                string recpath = (string)pii_table[result.PII];
                                writeLog?.Invoke($"发现读者记录 {item.RecPath} 的 PII '{result.PII}' 和 {recpath} 的 PII 重复了。跳过它");
                                continue;
                            }

                            pii_table[result.PII] = item.RecPath;

                            // TODO: PII 应该是包含 OI 的严格形态
                            context.Patrons.Add(item);

                            if ((i % 10) == 0)
                            {
                                await context.SaveChangesAsync(token);
                            }

                            i++;
                        }

                        await context.SaveChangesAsync(token);
                    }
                }

                writeLog?.Invoke($"plan.StartDate='{plan.StartDate}'。skip_count={skip_count}, error_count={error_count}。返回");

                return(new ReplicationPlan
                {
                    Value = (int)hitcount,
                    StartDate = plan.StartDate
                });
            }
            catch (Exception ex)
            {
                // 2020/9/26
                writeLog?.Invoke($"DownloadAllPatronRecord() 出现异常:{ExceptionUtil.GetDebugText(ex)}");

                return(new ReplicationPlan
                {
                    Value = -1,
                    ErrorInfo = $"DownloadAllPatronRecord() 出现异常:{ex.Message}"
                });
            }
            finally
            {
                channel.Timeout = old_timeout;
                App.CurrentApp.ReturnChannel(channel);

                writeLog?.Invoke($"结束下载全部读者记录到本地缓存");

                _inDownloadingPatron--;
            }
        }