#InterSystems IRIS for Health

0 关注者 · 862 帖子

InterSystems IRIS for Health™ 是全球第一个也是唯一一个专门为医疗应用程序的快速开发而设计的数据平台,用于管理全世界最重要的数据。它包括强大的开箱即用的功能:事务处理和分析、可扩展的医疗保健数据模型、基于 FHIR 的解决方案开发、对医疗保健互操作性标准的支持等等。所有这些将使开发者能够快速实现价值并构建具有突破性的应用程序。了解更多信息

文章 姚 鑫 · 七月 30, 2023 3m read

第七章 HL7 架构和可用工具 - 使用 HL7 消息查看器页面

使用 HL7 消息查看器页面

HL7 提供了消息查看器页面。可以使用此页面显示、转换和导出 HL7 消息(外部文件或来自生产消息存档的消息)。

要访问此页面,请选择互操作性 > 互操作 > HL7 v2.x > HL7 v2.x 消息查看器。

选择选项

要指定要显示的文档:

  1. 对于文档源,选择文件、消息标头 ID 或消息正文 ID
  2. 指定要显示的文档:
    • 如果选择“文件”,请使用“浏览”选择文件。对于文件中的文档编号,输入要显示的文档编号。
    • 如果选择了“消息标头 ID”或“消息正文 ID”,请键入要显示的消息标头或消息正文的 ID
  3. 指定如何解析文档。为此,请为文档结构或架构选择以下选项之一:
    • 由业务服务接收 — 使用由业务服务分配的架构。如果选择此选项,请从下拉列表中选择业务服务。 此选项使能够确定特定业务服务将此文档分配到的 DocType
    • 使用特定架构类别/版本 - 从下拉列表中选择文档类别。
    • 使用特定的 DocType — 以类别:结构格式输入文档结构 (<MessageStructure>) 的名称。解析器使用此文档结构。
    • 使用内容声明的版本:名称 — 使用与文档中声明的文档类型关联的文档结构。
    • 使用对象存储的 DocType — 使用文档正文对象中声明的 DocType。 (此选项不适用于从文件加载的存储文档。)
    • None — 不使用任何 DocType 来解析文档。相反,显示原始片段而不将它们转换为链接。

此选项使能够尝试将来自特定数据源的文档解释为不同的架构类别类型,以确定在处理来自该源的文档时使用哪种 DocType 是正确的。可能需要这样做的原因有多种。例如,可能会发现,当更新外部应用程序时,它已更改其发送的文档的实际版本,但忽略了更新其在这些文档中发送的类型声明。当文档使用自定义文档结构时,它还可用于确定将哪个内置类别用作架构基础。

  1. 或者单击“转换文档?”并指定转换详细信息。请参阅测试转换。
  2. 单击“确定”。

解析消息

完成上述步骤后,消息查看器会在屏幕右侧显示以下内容:

  • 摘要报告,其中包含有关该文档的以下基本信息:
    • 应用数据转换(如果适用)
    • 消息 ID
    • 文档类型
    • 文档类型类别
    • DocType 描述(如果有)
    • 段数
    • 子文件和父文件的数目(如适用)
  • 消息数据,消息结构中的每个段都有一行。每行包含:
    • 段数
    • 段名称,例如 PIDNTE
    • 消息中包含的字段内容和分隔符

如果消息与选择的架构匹配,段和元素将显示为蓝色,如下所示。单击段或字段将链接到相关的结构页面。

0
0 227
文章 姚 鑫 · 七月 27, 2023 3m read

第四章 HL7 架构和可用工具 - 查看数据结构

查看数据结构

当单击“数据结构”列中的名称时,InterSystems 会显示该数据结构中的所有字段。这是 HL7 数据结构页面。显示的以下列是最有用的:

  • 组件列列出了可用于访问段内字段的数字。
  • 属性名称列列出了可用于访问段内字段的名称。
  • 单击“数据结构”列中的条目可深入了解详细信息。
  • 单击“代码表”列(如果有)中的条目可查看可在此字段中输入的有效代码。

当单击上面段结构页面中名为 2.3:XCN 的数据结构项时,将出现以下示例页面。该页面指出类别 2.3 数据结构 XCN 描述“扩展复合 ID 号和名称”并由 14 个字段组成。其中,有些是简单值,有些是数据结构,有些是代码。

有了这些信息,就可以为消息结构 2.3:ADT_A01 中的复杂 PR1grp().PR1:Surgeon 字段创建虚拟属性路径,如下所示:

PR1grp().PR1:Surgeon.familyname
PR1grp().PR1:Surgeon.degree

查看代码表

当单击“代码表”列中的名称时,它会列出并解释该字段的有效代码。这是 HL7 代码表页面。当单击上一节中显示的数据结构页面中名为 2.3:200 的代码表项时,将出现以下示例页面。

上面的示例示出类别2.3代码表200描述可以具有值LOMACD的“名称类型”。

这意味着,如果有一条 DocType2.3:ADT_A01HL7 消息,则它具有一个可选虚拟属性,路径为 PR1grp().PR1:Anesthesiograph.nametype,可以包含以下值之一:LOMACD

使用自定义架构编辑器

自定义架构编辑器允许创建新的自定义 HL7 架构或编辑现有的自定义 HL7 架构。通常,自定义模式具有基本模式,它是标准模式或其他自定义模式。当 InterSystems 产品使用自定义架构来解析消息时,如果自定义架构中未定义消息类型、段或其他元素,它将使用基本架构中的定义。因此,只需在自定义架构中定义基本架构中不存在的元素,或者需要与基本架构中的定义不同的元素。无法编辑标准架构。

定义自定义架构的最常见原因是能够解析带有尾部 Z 段的 HL7 消息。 InterSystems 产品可以处理带有架构中未定义的尾部 Z 段的消息,但要执行以下任一操作,需要定义自定义架构:

  • 访问路由规则、数据转换或 ObjectScript 代码中尾部 Z 段中的字段路径。
  • 验证尾部 Z 段。

如果production当前正在使用标准模式,并且需要访问数据转换或路由规则中的尾部 Z 段字段路径,则应执行以下操作:

  1. 使用管理门户中的自定义架构编辑器创建新的 HL7 架构。输入自定义架构的名称并指定基本架构。请参阅创建新的自定义架构。
  2. 定义可以出现在消息中的 Z 段。如果 Z 段与基础架构中的现有段具有相似的字段,可以从基础复制定义,然后根据需要进行修改。否则,可以创建一个新段。可以添加字段、删除字段或更改字段的顺序。请参阅定义新段。
  3. 对于包含尾随 Z 段的每个消息类型,在从基础架构复制的自定义架构中创建消息类型和结构类型。将 Z 段添加到结构类型的末尾。请参阅定义新消息类型和结构类型
  4. 修改production 中的业务服务以使用新的自定义架构而不是基本架构。
  5. 通过向production的业务服务提供带有尾部 Z 段的新消息来测试production。如果在消息查看器中查看消息,则 Z 段(如果它们在架构中定义)将显示为蓝色。无法识别的段显示为黑色。
0
0 137
文章 姚 鑫 · 七月 26, 2023 3m read

第三章 HL7 架构和可用工具 - 使用 HL7 架构结构页面

使用 HL7 架构结构页面

通过 HL7 架构页面,可以导入和查看 HL7 版本 2 架构规范。要显示此页面,请从主页中选择互操作性 > 互操作 > HL7 v2.x > HL7 v2.x 架构结构。有关使用此页面的一般信息,请参阅在产品中使用虚拟文档中的“使用架构结构页面”。

HL7 模式页面提供了一个附加选项卡:消息类型。此选项卡将两个消息结构标识为请求/响应对。

查看文档类型列表

要列出某个类别中的所有文档类型结构,请首先选择该类别,然后单击“DocType 结构”选项卡。

查看消息结构

要查看消息结构的内部组织,请从 HL7 架构页面上的 DocType 结构选项卡单击其名称(选择互操作性 > 互操作 > HL7 v2.x > HL7 v2.x 架构结构)。 InterSystems 产品使用以下视觉提示和命名约定在“结构”部分中显示消息的段结构。

  • 组成消息结构的段按从上到下的顺序列出。
  • 段名称必须全部大写。
  • 显示每个消息段的三个字母名称:MSHNTEPID 等。该名称指示 HL7 消息结构中该位置存在的段类型。包含选项、重复或包含一组其他段的段的名称会在名称中附加特殊字符。
  • 绿色虚线包围可选的段、组或字段。
  • 可以重复的段在段名称后附加了括号。例如,如果PID段可以重复,则出现PID()
  • 包含其他段选择的段被视为段的联合。这些联合段的段名称后附加有“union”一词。只有联合中包含的段之一可以出现在消息结构内的该位置。
  • 包含一组段的段在段名称后附加了字母“grp”。要展开或折叠组,请使用组名称旁边的箭头图标。
  • 双击段名称可在单独的窗口中打开该段的结构。

查看段结构

要查看消息段的结构,请在与上一节中显示的示例类似的任何页面中单击其名称。 InterSystems 产品显示一个表格,其中列出了该段中的所有字段。这是 HL7 架构段结构页面。

例如,如果单击 2.3:ADT_A01 消息结构中的 PR1 段,InterSystems 产品将显示以下页面。

各列如下:

  • Field 字段 — 用于访问段内字段的数字。
  • Description 描述 — 字段的简短描述。
  • Property Name 属性名称 — 用于访问段内字段的名称。
  • Data Structure - 对于使用数据结构的更复杂的字段值,需要进一步的语法详细信息才能完成segment:field 虚拟属性路径。可以通过单击此列中的名称来获取此信息
  • Symbol 符号——表示字段的语法规则。此列中的字符指示是否可以预期此字段在消息段中存在、不存在或重复。可能的值
SymbolMeaning
!(仅限1)该字段为必填字段;它只能出现一次。
?(01)该字段是可选的,但如果发生,则可能只出现一次。
+(1个或多个)该字段可以重复一次或多次。
*(0或更多)该字段可以重复0次或多次。
&该字段可能存在,并且可能重复,但仅在某些条件下。
n*0n) 该字段最多重复 n 次。
  • Repeat Count - 该字段可以重复的最大次数(如果重复,并且有最大值)。
  • Minimum Length - 字段中的最小字符数。该字段的每次重复都必须包含此数量的字符。
  • Maximum Length - 字段中的最大字符数。该字段的每次重复都可以包含此数量的字符。
  • Required - 显示 R 表示必需,O 表示可选。
  • Repeating - 显示 1 表示 true0 表示 false
  • Code Table - 单击条目可查看可在此字段中输入的有效代码。
  • Alternate Description替代描述 - 该领域的第二个更长的描述。

可以使用此信息(尤其是“属性名称”列)以“段:字段”格式构建虚拟属性路径。以下是涉及 2.3:ADT_A01 消息结构中 PR1 段的简单字段值的虚拟属性路径示例。 () 快捷语法指示重复字段的所有可用实例,而 (1) 指示第一个实例:

PR1grp().PR1:ProcedureType
PR1grp().PR1:ProcedureCode()
PR1grp().PR1:ProcedureCode(1)
PR1grp().PR1:ProcedureCode(x)
PR1grp().PR1:ProcedurePriority

0
0 102
文章 姚 鑫 · 七月 25, 2023 3m read

第二章 HL7 架构和可用工具 - HL7 模式和消息概述

HL7 模式和消息概述

InterSystems 产品可以处理和传递 HL7 消息,而无需使用架构来解析它,但将架构与消息关联允许执行以下操作:

  • 解析消息并访问以下字段值:
    • 数据转换
    • 路由规则
    • 自定义 ObjectScript 代码
  • 验证消息是否符合架构。

每个 HL7 消息均由消息类型标识,该消息类型在 MSHMessageType 字段 (MSH:9) 中指定。一些消息类型共享相同的消息结构。例如,在HL7版本2.3.1中,用于预先接纳患者的ADT_A05消息具有与ADT_A01接纳消息相同的结构。该架构指定 ADT_A05 消息具有结构类型 ADT_A01

为了解析 HL7 消息,需要两条信息:

  • 架构类别 — 这是 HL7 版本号,例如 2.3.12.7,或者它可能是 InterSystems 产品中定义的自定义架构的类别。production 从业务服务消息模式类别设置或从数据转换设置获取模式类别。尽管 HL7 消息在 MSHVersionID 字段中包含模式版本号 (MSH:12),但 InterSystems 不使用此值,因为许多应用程序并未一致地设置此字段。
  • 结构类型 - productionMSH:9 字段获取消息类型,然后检查架构定义以获取该消息的结构类型。

在某些情况下,使用 MSH:9.3 子字段来限定消息类型。 MSH:9:3 子字段在 HL7 消息中以两种方式使用:1) 作为消息类型的修饰符,或 2) 指定结构类型。如果 MSH:9:3 修改消息类型(通常为数字),InterSystems 产品会将其作为消息类型的一部分。如果 MSH:9:3 指定结构类型(例如 ADT_A01),则 InterSystems 在确定消息类型和设置 Name 属性时都会忽略它。 InterSystems 产品不需要 MSH:9.3 子字段来确定结构类型,因为它们从架构中获取结构类型。

当业务服务或数据转换创建 EnsLib.HL7.Message 对象来存储 HL7 消息时,它会组合架构类别和结构类型,并使用以下语法将其存储在 DocType 属性中:

category:structureType

例如,类别 2.3.1 的有效 DocType 值包括 2.3.1:ACK2.3.1:ADT_A172.3.1:BAR_P012.3.1:PEX_P07。消息类型可以与结构类型不同,存储在 Name 属性中。

如果在 ObjectScript 代码中创建 EnsLib.HL7.Message 对象,则应根据 MSH:9 字段中的值设置 DocTypeName 属性。

HL7 标准允许本地扩展,例如尾部 Z 段。这些段未在基本架构类别中定义。如果要访问数据转换、路由规则或 ObjectScript 中自定义 Z 段中的字段,则需要定义指定扩展消息的自定义架构类别。

可以将自定义 HL7 架构置于源代码管理之下。启用源代码控制后,源代码控制选项(例如签出和签入)可从主 HL7 模式页面使用,但在用于处理自定义模式的其他页面(例如 HL7 模式消息类型页面)上不可用。在使用其他页面编辑架构之前,必须从 HL7 架构页面检查整个架构。 HL7 模式主页面提供了源代码控制输出窗口,该窗口捕获所有相关 HL7 模式页面的源代码控制活动。有关设置源代码控制的信息,请参阅将 IRIS 与源代码控制系统集成。

1
0 153
文章 姚 鑫 · 七月 23, 2023 3m read

第六十七章 开发Productions - ObjectScript Productions - Production品及其零部件的生命周期 - BO和适配器的生命周期

BO和适配器的生命周期

IRIS 自动管理每个业务操作的生命周期。

Production Startup

Production生产(或更改特定业务操作的配置)时, IRIS 自动为每个配置的业务操作类(即,为Production定义中列出的每个业务操作)执行以下任务:

  1. 它调用类的 OnProductionStart() 回调方法(如果已定义)。

OnProductionStart() 方法是一种类方法,它为Production配置中列出的每个业务操作类调用一次。业务操作类可以使用此回调来执行它可能需要的任何类范围的初始化。

  1. 它创建一个或多个后台进程来执行业务操作。

后台进程的数量由Production配置中业务操作的 PoolSize 属性决定。每个后台进程都称为业务操作的实例,并包含业务操作对象的实例。

如果满足以下条件, IRIS 只会为业务操作创建后台进程:

  • 业务操作类必须将其INVOCATION类参数设置为Queue
  • Production配置中业务操作的 Enabled 属性必须设置为 1(否则业务操作被视为已禁用)。已禁用的业务操作仍具有传入消息队列。在启用业务操作之前,不会处理发布到此队列的任何请求。
  • Production配置中业务操作的 PoolSize 属性必须设置为大于 0 的值。

如果Production配置中业务操作的 Foreground 属性设置为 1,则 IRIS 将为业务操作创建一个前台进程(即,它将创建一个终端窗口)。此功能有利于测试和调试。

  1. 它初始化系统监控信息,用于监控业务运行的状态和运行历史。

  2. 在每个后台进程中:

    1. IRIS 创建业务操作类的实例,提供任何业务操作设置的最新配置值,并调用业务操作 OnInit() 回调方法(如果存在)。 OnInit() 方法是一个实例方法,它提供了一个方便的地方来执行业务操作的任何初始化逻辑。
    2. 创建关联适配器类的实例(如果已定义)并提供任何适配器设置的最新配置值。

Runtime

在运行时,业务操作执行以下操作:

  1. 它等待请求(从业务服务、业务流程和其他业务操作)发送到其关联的消息队列。
  2. 当业务操作从其消息队列中检索到请求后,它会在其消息映射中搜索与该请求类型对应的操作方法。然后它调用该操作方法。
  3. 操作方法使用请求对象中的数据向外部应用程序发出请求。通常,它通过调用其关联的出站适配器对象的一个或多个方法来完成此操作。

Production Shutdown

Production停止时,会发生以下与业务运营相关的事件:

  1. IRIS 等待每个业务操作达到静止状态(即, IRIS 等待每个业务操作完成其所有同步请求)。
  2. 调用每个出站适配器中的 OnTearDown() 方法。
  3. 所有出站适配器和业务操作对象都被销毁,并且它们的后台进程被终止。
  4. 每个业务操作的 OnProductionStop() 类方法都会针对生产中该类的每个配置项调用一次。

当系统管理员禁用业务操作或根据其配置的计划变为非活动状态时,Production将继续运行,但关联的出站适配器将关闭,并执行其 OnTearDown() 方法。

0
0 127
文章 姚 鑫 · 七月 22, 2023 3m read

第六十六章 开发Productions - ObjectScript Productions - Production品及其零部件的生命周期 - 业务流程的生命周期

业务流程的生命周期

每次Production启动时, IRIS都会为Production创建公共参与者池。ActorPoolSize设置的值确定池中的作业数。

在执行元池中的每个作业中,都有一个Ens.ActorEns.在一个对象中,该对象负责管理业务流程对其作业的使用。在一个Ens.Actor时称为执行元。

Production中的业务流程可以共享名为 Ens.Actor 的公共消息队列。此公共队列是发送到生产中没有自己的专用队列的任何业务流程的所有消息的目标。只要 Actor 有空托管业务流程,它们就会监听 Ens.Actor 队列。当请求到达 Ens.Actor 队列时,任何空闲的参与者都可以分配其作业来托管请求中指定的业务流程。 Ens.Actor 队列上的请求按照接收顺序进行处理。每个连续的请求都由下一个可用的参与者持续声明。

与业务服务和业务操作的生命周期不同,业务流程的OnInitOnTearDown 方法不会在业务流程启动或停止时被调用。相反,每次业务流程(InProcQueued)处理请求时都会执行这些方法。可以实现业务流程类的 OnProductionStart 方法,以在Production开始或业务流程重新启动时执行自定义代码。当Production停止时,将调用该类的 OnProductionStop 方法。

公共队列中的生命周期

一个使用公共队列的业务流程的生命周期如下:

  1. 初始请求发送至业务流程。请求消息到达 Ens.Actor 队列。
  2. 一旦 Actor 可用,它就会从 Ens.Actor 队列中提取请求消息。
  3. 参与者创建适当业务流程类的新实例。调用业务流程的 OnInit() 方法。参与者提供业务流程设置的最新值并调用该实例的 OnRequest() 方法。业务流程实例现在正在进行中。
  4. 当业务流程实例正在进行时,只要它不活动(例如,当它正在等待输入或反馈时),它通常会将控制权返回给实例化它的参与者。当这个情况发生时:

a. 参与者暂停业务流程实例。

b. 参与者将实例的当前状态保存到磁盘。

c. 参与者将其工作返回到参与者池。

  1. 只要正在进行的业务流程没有分配的参与者,并且后续请求或响应到达该业务流程(例如,当预期的输入或反馈到达时),就会发生以下顺序:

a. 当参与者可用时,它从Ens.Actor队列中提取新的请求或响应消息。

b. 参与者从磁盘恢复相应的业务流程对象,并完成其所有状态信息。

c. 执行元根据需要调用OnRequest()OnResponse()实例方法。

  1. 在业务流程实例完成执行后,其当前参与者调用其OnComplete()方法并将该实例标记为IsComplete状态。actor还会将其工作返回到actor池。不会将进一步的事件发送到此业务流程实例。调用业务流程的OnTearDown方法。

专用队列中的生命周期

或者,可以将业务流程配置为具有私有队列,从而绕过公共Ens.Actor队列。具有专用队列的业务流程的生命周期与公共队列的描述完全相同,只是:

  • 业务流程仅在私有池中的作业中运行。
  • 发送至此业务流程的消息到达其自己的专用队列,并且不会到达 Ens.Actor 队列。
0
0 109
文章 姚 鑫 · 七月 21, 2023 3m read

第六十五章 开发Productions - ObjectScript Productions - Production品及其零部件的生命周期 - Runtime

Runtime

Production运行时,业务服务会重复调用入站适配器的 OnTask() 方法。此 OnTask 循环由业务服务的 CallInterval 设置和 %WaitForNextCallInterval 属性控制,如下所示:

  1. 业务服务调用入站适配器的 OnTask() 方法。
  2. OnTask()IRIS 生产外部检查业务服务感兴趣的输入事件:
  • 如果找到输入,OnTask() 将调用关联业务服务对象的 ProcessInput() 方法。
  • 如果未找到输入,OnTask() 将控制权返回给业务服务,业务服务等待下一个 CallInterval 过去,然后返回到步骤 1
  • 可能存在多个输入事件。例如,如果业务服务使用File.InboundAdapter,则可能有多个文件在指定目录中等待。

如果有多个输入事件:

  • 通常,OnTask() 方法会根据需要多次调用 ProcessInput() 来处理所有可用的输入事件,直到找不到更多输入事件为止。
  • 或者,入站适配器可以限制 OnTask() 在每个 CallInterval 中仅调用一次 ProcessInput(),即使存在多个输入事件也是如此。 OnTask() 在处理找到的第一个事件后进入休眠状态,而不是处理所有输入事件。
  1. ProcessInput() 将业务服务 %WaitForNextCallInterval 属性设置为 0 (false) 并调用 OnProcessInput() 来处理输入事件。
  2. 完成后,ProcessInput() 将控制返回给 OnTask()
  3. 此时,OnTask() 可以将 %WaitForNextCallInterval 设置为 1 (true)。这限制了业务服务在每个 CallInterval 中仅处理一个输入事件,即使存在多个输入事件也是如此。

通常希望业务服务立即处理所有可用的输入事件,因此通常不希望在此步骤执行任何更改 %WaitForNextCallInterval 的操作。它应该保留 ProcessInput() 设置的 0(假)值。

适配器基类 Ens.InboundAdapter 具有调用 ProcessInput()OnTask() 方法,将 %WaitForNextCallInterval 设置为 1,然后返回。

提示:如果只是希望业务服务在每个 CallInterval 唤醒并运行其 ProcessInput() 方法一次而不关心 IRIS 之外的事件,请在使用适配器类 Ens.InboundAdapter

  1. OnTask() 返回。
  2. 业务服务测试其 %WaitForNextCallInterval 属性的值:
  • 如果为 1 (true),业务服务将等待 CallInterval 结束,然后返回到步骤 1
  • 如果为 0(假),业务服务立即返回到步骤 1。直到 OnTask() 发现没有更多输入(请参阅步骤 2),CallInterval 才会发挥作用。

Production Shutdown

Production停止时,会发生以下与业务服务相关的事件:

  1. IRIS 禁用每项业务服务;不再接受此制作的传入请求。
  2. 调用每个入站适配器中的 OnTearDown() 方法。
  3. 所有入站适配器和业务服务对象都将被销毁,并且它们的后台进程将被终止。
  4. 每个业务服务的 OnProductionStop() 类方法都会针对生产中该类的每个配置项调用一次。

当系统管理员禁用业务服务或根据其配置的计划变为非活动状态时,Production将继续运行,但关联的入站适配器将关闭,并执行其 OnTearDown() 方法。

0
0 102
文章 姚 鑫 · 七月 20, 2023 3m read

第六十四章 开发Productions - ObjectScript Productions - Production品及其零部件的生命周期

此页面描述了Production及其组成部分的生命周期,以供参考。

Production的生命周期

Production启动

Production开始时,动作顺序如下:

  1. Production类被实例化;其可选的 OnStart() 方法执行。
  2. Production实例化每个业务操作并执行其可选的 OnProductionStart() 方法。
  3. Production实例化每个业务流程并执行其可选的 OnProductionStart() 方法。
  4. Production会清除上一次运行遗留的任何指标值的业务指标缓存。
  5. Production实例化每个业务服务并执行其可选的 OnProductionStart() 方法。
  6. Production过程处理已放入队列中的所有项目。这包括Production停止时排队的异步消息。
  7. Production现在接受来自外部 IRIS 的输入。

Production Shutdown

Production停止时,操作顺序如下:

  1. Production使每个业务服务脱机并执行其可选的 OnProductionStop() 方法。此操作会停止来自 IRIS 外部的所有请求。
  2. 所有业务主机都会收到进入静止状态的信号。
  3. 所有队列都进入静止状态。这意味着从现在开始,业务主机只能处理具有高优先级的队列消息(同步消息)。异步消息保留在各自的队列中。
  4. Production环境尽最大努力完成所有同步消息的处理。
  5. Production使每个业务流程脱机并执行其可选的 OnProductionStop() 方法。
  6. Production使每个业务操作脱机并执行其可选的 OnProductionStop() 方法。
  7. Production下线。 IRISProduction类中执行可选的 OnStop() 方法。

业务服务和适配器的生命周期

Production启动

当开始Production(或更改特定业务服务的配置)时, IRIS 会自动为每个配置的业务服务类(即生产定义中列出的每个业务服务)执行以下任务:

  1. IRIS 调用业务服务的 OnProductionStart() 回调方法(如果已定义)。

OnProductionStart() 方法是一个类方法,为Production配置中列出的每个业务服务类调用一次。业务服务类可以使用此回调来执行它可能需要的任何类范围的初始化。如果业务服务没有适配器,业务服务类可以使用此回调来检查错误。

  1. IRIS 创建一个或多个后台进程来执行业务服务。

后台进程的数量由Production配置中业务服务的 PoolSize 属性决定。每个后台进程被称为业务服务的实例,并且包含业务服务对象的实例。

如果满足以下条件,IRIS 仅会为业务服务创建后台进程:

  • 业务服务类必须具有由其 ADAPTER 类参数指定的关联入站适配器类。

没有关联入站适配器的业务服务类称为“无适配器服务”。此类服务不是等待外部事件,而是在进程内调用(可能由复合应用程序调用)。

  • Production配置中业务服务的 Enabled 属性必须设置为 1(否则业务服务将被视为已禁用且不会接受输入)。
  • Production配置中业务服务的 PoolSize 属性必须设置为大于 0 的值。

如果Production配置中业务服务的 Foreground 属性设置为 1,则 IRIS 将为业务服务创建一个前台进程(即 IRIS 将创建一个终端窗口)。此功能有利于测试和调试。

  1. IRIS 初始化系统监控信息,用于监控业务服务的状态和运行历史。

  2. 在每个后台进程中,IRIS 执行以下操作:

a. 创建业务服务类的实例。

b. 提供任何业务服务设置的最新配置值

c. 调用业务服务的 OnInit() 回调方法(如果存在)。OnInit() 方法是一个实例方法,它提供了一个方便的位置来执行业务服务的任何初始化逻辑。

d. 创建关联适配器类的实例(如果已定义)并提供任何适配器设置的最新配置值。

0
0 92
文章 姚 鑫 · 七月 19, 2023 2m read

第六十三章 开发Productions - ObjectScript Productions - 部署Production - 在目标系统上部署Production

管理门户自动执行将Productions从开发系统部署到实时系统的过程。本节介绍当在实时系统上加载Productions的新版本时,IRIS 会执行哪些操作。

获得部署包 XML 文件后,可以将其加载到目标系统上。在管理门户中,选择正确的命名空间并单击互操作性、管理、部署更改、部署,然后单击打开部署或打开本地部署按钮,具体取决于 XML 部署包位于服务器上还是本地计算机上。如果位于服务器计算机上,则“打开本地部署”按钮不处于活动状态。选择 XML 部署包文件后,表单会列出部署包中的新项和更改项,显示创建包时指定的部署说明,并允许指定以下部署设置:

  • 目标Production —指定将添加组件的Production。如果部署包包含来自源ProductionProduction类,则目标Production将设置为源Production且无法更改。否则, IRIS 将默认Production设置为当前打开的Production,但允许更改它。
  • 回滚文件—指定包含回滚信息的文件。回滚文件包含由部署替换的所有组件的当前定义。
  • 部署日志文件—包含由部署引起的更改的日志。

阅读部署说明并对部署设置进行任何更改后,单击“部署”按钮完成部署。作为部署包的一部分, IRIS 会执行以下操作来停止Production、加载新代码,然后重新启动Production

  1. 创建并保存回滚包。
  2. 禁用Production中在部署包中具有Production设置 (ptd) 文件的组件。
  3. 导入 XML 文件并编译代码。如果编译任何组件时出错,整个部署都会回滚。
  4. 更新Production设置。
  5. 编写详细说明部署的日志。
  6. 如果当前设置指定启用已禁用的Production组件,则启用它们。

要撤消此部署更改的结果,请使用“打开部署”按钮选择回滚文件,然后单击“部署”按钮。

0
0 150
文章 姚 鑫 · 七月 18, 2023 4m read

第六十二章 开发Productions - ObjectScript Productions - 部署Production - 导出Production

导出Production

要使用管理门户导出ProductionXML,请打开Production,单击Production设置和操作选项卡,然后单击导出按钮。 IRIS 选择所有业务服务、业务流程、业务操作和一些相关类,然后显示以下表单以允许添加导出注释和其他组件。

还可以导出业务服务、流程或操作,方法是在Productions配置中选择组件,然后单击“操作”选项卡上的“导出”按钮。在这两种情况下,都可以通过单击其中一个按钮并选择一个组件来将其他组件添加到包中。以通过清除该复选框来从包中删除组件。

可以使用导出注释来描述部署包中的内容。例如,可以描述完整的Productions是否位于作为Productions更新的包或组件集中。当使用管理门户将包部署到目标系统时,会显示导出注释。

当导出部署包时,应该做出的第一个决定是目标系统是否具有旧版本的Productions

如果将Productions部署为新安装,应该:

  • 包括Production类的定义。
  • 包括Production设置。
  • 包括Production中使用的所有组件的定义。
  • 排除每个组件的Production设置(ptd 文件)。这将重复Production类中的定义。

如果要部署Production来更新Production的实时版本,应该:

  • 排除Production类的定义。
  • 排除Production设置,除非有更改并且想要覆盖任何本地设置。
  • 包括所有已更新组件的定义。
  • 包含其设置已更改或在导入和编译 XML 之前应禁用的任何组件的Production设置 (ptd) 文件。

尽管默认情况下包中包含许多组件,但必须通过选择“添加到包”部分中的按钮之一来手动添加其他组件。例如,如果Production中使用了以下任何一项,需要手动添加它们:

  • 记录映射——包括定义和生成的类。
  • 复杂的记录映射——包括定义的和生成的类。
  • 查找表
  • 代码中引用的用户类
  • 设置为可部署的系统默认设置或计划规范

Production Settings 按钮允许添加生产 ptd 文件。该 XML 定义了以下内容:

  • Production comments
  • General pool size
  • 是否启用测试以及是否应记录跟踪事件。

可以通过清除其复选框来取消选择列表中的任何组件。可以通过选中其框来选择组件。 “全选”按钮会选中所有复选框,“取消全选”按钮会清除所有复选框。

选择部署包的组件后,通过单击导出来创建它。可以通过浏览器的下载功能将导出文件保存到服务器或本地。如果将其导出到服务器,则可以指定文件位置。如果通过网络浏览器导出,则可以指定文件名。

部署包包含有关其创建方式的以下信息:

  • 运行 IRIS 的系统名称
  • 包含Production式的命名空间
  • 来源Production名称
  • 导出Production的用户
  • 导出Production时的 UTC 时间戳

应该在开发系统上保留部署文件的副本。可以使用它来创建一个新的部署包,其中包含对组件的最新更改。保留部署文件的副本使无需手动选择要包含在部署文件中的组件。

要使用现有部署包来选择组件来创建新的部署包,请执行以下操作:

  1. 在具有更新Production的开发系统上,单击“Production设置”和“操作”选项卡,然后单击“重新导出”按钮。
  2. 选择包含旧部署包的文件。
  3. IRIS 从当前Production中选择旧部署包中包含的相同组件。
  4. 如果旧部署包中缺少任何组件,或者已将新组件添加到Production中,请手动添加缺少的组件。
  5. 单击“导出”按钮以保存包含更新组件的新部署包。

注意:如果ProductionXML 文档使用 XSD 架构,或对 X12 文档使用旧格式架构,则这些架构不会包含在 XML 部署文件中,并且必须通过其他机制进行部署。 IRIS 可以以当前格式、旧格式或两种格式存储 X12 模式。创建部署文件时,它可以包含当前格式的 X12 架构,但不包含任何旧格式的 X12 架构或 XML 文档的任何 XSD 架构。如果Production使用旧格式 X12 架构或使用任何 XSD XML 架构,则必须独立于部署Production来部署架构。对于没有包含在部署文件中的schema,可以通过以下方式之一部署到目标系统:

  • 如果 XMLX12 架构最初是从 XSDSEF 文件导入的,并且该文件仍然可用,请通过导入该文件来导入目标系统上的架构。 XSD 文件可用于导入 XML 架构,SEF 文件可用于导入 X12 架构。
  • 导出包含架构的基础 IRIS Global,然后将其导入目标系统。要导出Global,请选择系统资源管理器 > Global,选择所需的Global,然后选择导出。 X12 架构存储在 EnsEDI.DescriptionEnsEDI.SchemaEnsEDI.X12.DescriptionEnsEDI.X12.Schema Global变量中。XML 架构存储在 EnsEDI.XML.Schema Global中。
0
0 130
文章 姚 鑫 · 七月 17, 2023 3m read

第六十一章 开发Productions - ObjectScript Productions - 部署Production

部署Production

通常,在开发系统上开发Production,然后在测试部署上完成并测试生产后,将其部署在实时生产系统上。本页介绍如何使用管理门户打包开发系统中的部署,然后将其部署到另一个系统上。它还描述了如何开发和测试对生产的更改,然后将这些更新部署到使用实时业务数据运行的系统。

部署Production概述

可以使用管理门户或 IDE 来部署Production。管理门户会自动执行一些需要使用 IDE 手动执行的步骤。如果有正在使用的实时Production,并且正在开发该Production的更新,则需要确保在不中断业务数据处理的情况下更新实时Production。在最简单的层面上,部署Production是通过从一个系统导出ProductionXML 定义并在目标系统上导入和编译 XML 来完成的。从开发到上线系统的成功部署最重要的问题是:

  • 确保 XML 部署文件具有所有必需的组件。
  • 在将部署文件部署到实时系统之前,先在测试系统上测试部署文件。
  • 确保部署文件加载到目标系统上而不中断实时Production

通常,将Production部署到实时系统是一个迭代过程,包括以下步骤:

  1. 从开发系统导出Production
  2. 在测试系统上部署部署文件。
  3. 确保Production具有所有必需的组件并在测试系统上正常运行。如果发现任何故障,请修复它们并重复步骤 1
  4. Production部署到测试系统且没有错误后,将部署文件部署到实时系统。监控实时系统以确保Production继续正确运行。

应该确保测试系统环境与实际系统的环境尽可能匹配。如果正在更新现有Production,则在应用更新之前,测试系统上的Production应与实时系统上的Production相匹配。如果要在新的 IRIS 安装上部署Production系统,则测试系统应该是新的 IRIS 安装。

为了更新正在运行的Production中的组件,必须执行以下操作:

  • 在系统上加载更新的 XML
  • 编译 XML
  • 通过禁用并重新启用组件,将组件的运行实例更新为新代码。

根据目标系统是否已经运行Production版本,部署过程略有不同。如果目标系统正在运行旧版本的Production,那么部署文件应该只包含更新的组件和一些配置项,并且在大多数情况下,它不应该包含Production类的定义。如果目标系统不包含Production系统,则部署文件应包含所有Production组件和设置。如果使用互操作性 > 管理 > 部署更改 > 部署管理门户页面将更新部署到正在运行的Production,门户会自动执行以下操作:

  1. 创建回滚和日志文件。
  2. 禁用部署文件中具有配置项的组件。
  3. 导入并编译 XML。如果出现编译错误,门户会自动回滚部署。
  4. 启用禁用的组件

在某些情况下,必须明确停止并重新启动组件或整个Production。如果使用 IDE 或从管理门户系统资源管理器导入类,则必须手动执行这些步骤。

为了导出和部署Production,必须具有适当的权限,例如:

  • %Ens_Deploy:用于访问互操作性 > 管理 > 部署更改页面和部署操作
  • %Ens_DeploymentPkg:用于将 XML 导出到服务器
  • %Ens_DeploymentPkgClient:WRITE 使用 Web 浏览器在本地导出 XML
  • %Ens_DeploymentPkgClient:用于使用 Web 浏览器部署 XML

默认情况下,这些资源仅自动授予具有 %EnsRole_Administrator 角色的用户。

0
0 99
文章 姚 鑫 · 七月 16, 2023 13m read

一篇文章了解IRIS/Caché编码方案

一直以来,编码问题像幽灵一般,不少开发人员都受过它的困扰。

试想你请求一个数据,却得到一堆乱码,丈二和尚摸不着头脑。有同事质疑你的数据是乱码,虽然你很确定传了UTF-8 ,却也无法自证清白,更别说帮同事 debug 了。

有时,靠着百度和一手瞎调的手艺,乱码也能解决。尽管如此,还是很羡慕那些骨灰级程序员。为什么他们每次都能犀利地指出问题,并快速修复呢?原因在于,他们早就把编码问题背后的各种来龙去脉搞清楚了。

ASCII

标准ASCII 码,使用7 位二进制数(最高位为0)来表示所有的大写和小写字母,数字09、半角标点符号,以及在英语中使用的特殊控制符号。

最早只有127个字母被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母a的编码是97,小写字母z的编码是122

IRIS/Caché中获取字符ASCII码与二进制字符串,如下代码示例:

USER>w $a("a")
97
USER>w ##class(M.Code).LogicalToDisplay(97)
10000110

经过如下二进制转十进制计算可得出 1+32+64 = 97

2**0 + 2**5 + 2**6 = 97

Unicode

GB2312GBKGB18030 都是中文编码字符集。不同国家也推出了自己的字符集和编码方案,彼此不兼容。例如中文编码集,在日文系统无法正常显示,无法适应全球化应用。为了适应全球化,由统一码联盟开发,指定了统一码(Unicode),也叫万国码、单一码,是计算机科学领域里的一项业界标准,包括字符集、编码方案等。

Unicode已经收录的字符数量已经超过 13 万个,每个字符需占用超过 2 字节。由于常用编程语言一般没有 24 位数字类型,因此一般用 32 位数字表示一个字符。如果要用到非常偏僻的字符,就需要4个字节这样一来。同样的一个英文字母,在 ASCII中只需占用 1 字节,在 Unicode 则需要占用4 字节!

IRIS/Caché中获取字符Unicode编码,如下代码示例:

ClassMethod UnicodeEncode(str As %String) As %String
{
	q $replace($zcvt(str, "O", "URL"),"%","\")
}
USER>w ##class(Util.Impl.EncryptionUtils).UnicodeEncode("姚鑫")
\u59DA\u946B

UTF8

UTF-8Unicode的实现方式之一。UTF-8是一种 Unicode 的编码方式,主要作用对 Unicode 码的数据进行转换,转换后方便存储和网络传输。本着节约的精神,又出现了把Unicode编码转化为“可变长编码”的UTF-8编码(unicode transformation format)。UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节。如果你要传输的文本包含大量英文字符,用UTF-8编码就能节省空间。

Unicode符号范围 (十六进制)UTF-8编码方式(二进制)
0000 0000-0000 007F0xxxxxxx
0000 0080-0000 07FF110xxxxx 10xxxxxx
0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

IRIS/Caché中获取字符ASCII码与UTF8十六进制字符串,如下代码示例:

USER>w $a("鑫")
37995
USER>w $zhex(37995)
946B

GB2312、GBK和GB18030

ASICIIGB2312GBKGB18030 之间的关系可以用下图表示:

image

GB2312 兼容 ASICII 编码, GBK 兼容 GB2312 编码,GB18030 兼容 GB2312 编码 和 GBK 编码。

实际生活中,我们用到的 99% 的汉字,都属于 GB2312 编码范围 ,GB2312 每个编码对应的是哪个汉字可以参考 GB2312简体中文编码表, GBK 编码可以参考 GBK编码表, GB18030 可以参考 GB18030-2005 文档。

那么GB系列是如何兼容ASCII码的呢?

GB系列中,如果一个字节最高位 b80 ,该字节便是单字节编码,即 ASCII 码。如果字节最高位 b81 ,它就是双字节编码的首字节,与其后字节一起表示一个字符。

下图为GBK码表:

image

可以根据码表查对应汉字或全角字符对应的十六进制码表值,图中全角符号对应的GBK码表值为A1B6

ASICIIGB2312GBKGB18030Unicode之间的关系可以用下图表示:

image

ANSI

不同的国家和地区制定了不同的标准,由此产生了 GB2312GBKGB18030Big5Shift_JIS 等各自的编码标准。这些使用多个字节来代表一个字符的各种汉字延伸编码方式,称为 ANSI 编码。在简体中文Windows操作系统中,ANSI 编码代表 GB2312编码;在繁体中文Windows操作系统中,ANSI编码代表Big5;在日文Windows操作系统中,ANSI 编码代表 JIS 编码。

下图中文Windows环境中的ANSI编码为GB18030.

image

IRIS/Caché中验证ANSI是否为GB18030

ClassMethod GBK(filename)
{
	s stream = ##class(%Stream.FileCharacter).%New()
	#; 默认使用GB18030解码
	s stream.TranslateTable = "GB18030"
	s stream.Filename = filename
	w "字符长度:",stream.Size,!
	while 'stream.AtEnd {
		s line = stream.Read()
		w line,!
	}
	q $$$OK
}
USER>w ##class(M.Code).GBK("E:\m\code\gbk.txt")
字符长度:94
《过零丁洋》宋朝·文天祥
 
辛苦遭逢起一经,干戈寥落四周星。
 
山河破碎风飘絮,身世浮沉雨打萍。
 
惶恐滩头说惶恐,零丁洋里叹零丁。
 
人生自古谁无死?留取丹心照汗青。
 
1

在程序中还是用GB18030编码方式可以解析出中文,所以验证ASNI在中文环境中的编码格式为GB18030,如果是GB2312也可以正常解析出,因为是GB18030是向下兼容的。

手写解析UTF8编码

首先创建一个UTF8txt文件。

image

通过如下代码去解析UTF8文件,其中代码s stream.TranslateTable = "UTF8"指定解析方式。

ClassMethod UTF8(filename)
{
	s stream = ##class(%Stream.FileCharacter).%New()
	s stream.Filename = filename
	s stream.TranslateTable = "UTF8"
	w "字符长度:",stream.Size,!
	while 'stream.AtEnd {
		s line = stream.Read()
		w line,!
	}
	q $$$OK
}

可以正常解析出:

USER>w ##class(M.Code).UTF8("E:\m\code\utf8.txt")
字符长度:94
《过零丁洋》宋朝·文天祥
 
辛苦遭逢起一经,干戈寥落四周星。
 
山河破碎风飘絮,身世浮沉雨打萍。
 
惶恐滩头说惶恐,零丁洋里叹零丁。
 
人生自古谁无死?留取丹心照汗青。
 
1

如果不指定s stream.TranslateTable = "UTF8"该代码将会得到如下数据:

USER>w ##class(M.Code).UTF8("E:\m\code\utf8.txt")
字符长度:133
銆婅繃闆朵竵娲嬨?嬪畫鏈澛锋枃澶╃ゥ
 
杈涜嫤閬?㈣捣涓?缁忥紝骞叉垐瀵ヨ惤鍥涘懆鏄熴??
 
灞辨渤鐮寸椋庨绲紝韬笘娴矇闆ㄦ墦钀嶃??
 
鎯舵亹婊╁ご璇存兌鎭愶紝闆朵竵娲嬮噷鍙归浂涓併??
 
浜虹敓鑷彜璋佹棤姝伙紵鐣欏彇涓瑰績鐓ф睏闈掋??
 
1

那么在无法指定编码方式的字符串当中,该如何解析UTF8编码呢?根据UTF8的编码规则编写如下RAW2UTF8方法。

方法逻辑如下:

  1. 读取1个首部字符判断UTF8所占字节大小。

  2. 获取该字符的2进制字符串。

  3. 如果为ASCII码,长度小于8位,高位补0

  4. 如果UTF8为4字节,一般为不常见的汉字。

  5. 如果UTF83字节,一般为常用汉字。

    1. 去掉标识高位
    2. 取剩余字符
    3. 将剩余字符进行二进制字符串拼接
    4. 获取该字符的十进制ASCII
  6. 如果UTF81字节 ASCII码直接取值。

ClassMethod RAW2UTF8(stream As %Stream.FileBinary) As %String
{
	s str = ""
	
	while 'stream.AtEnd {
		
		#; 读取1个首部字符判断UTF8所占字节大小
		s content = stream.Read(1)
		
		#; 获取该字符的2进制字符串
		s ascii = $a(content)
		s highBit = ..LogicalToDisplay(ascii)
		
		#; 长度小于8位,高位补0
		if ($l(highBit) < 8) {
			s highBit = highBit _ ..Repeat(0, 8 - $l(highBit))
		}
		
		#; UTF8,4字节,一般为不常见的汉字
		if ($e(highBit,4, *) = "01111") {
			s bitStr =  $e(highBit, 1, 5)
			for i = 1 : 1 : 3 {
				s lowChar = stream.Read(1)
				s bitStr = $e(..LogicalToDisplay($a(lowChar)), 1, 6) _ bitStr 
			}
			s utf8num = ..BitToDec(bitStr)
		
		#; UTF8,3字节,一般为汉字
		} elseif ($e(highBit, 5, *) = "0111") {
			
			#; 去掉标识高位
			s bitStr =  $e(highBit, 1, 4)
			
			#; 取剩余字符
			for i = 1 : 1 : 2 {
				s lowChar = stream.Read(1)
				
				#; 将剩余字符进行二进制字符串拼接
				s bitStr = $e(..LogicalToDisplay($a(lowChar)), 1, 6) _ bitStr 
			}
			
			#; 获取该字符的十进制ASCII
			s utf8num = ..BitToDec(bitStr)

		#; UTF8,2字节
		} elseif ($e(highBit, 6, *) = "011") {
			s bitStr =  $e(highBit, 1, 3)
			for i = 1 : 1 : 1 {
				s lowChar = stream.Read(1)
				s bitStr = $e(..LogicalToDisplay($a(lowChar)), 1, 6) _ bitStr 
			}
			s utf8num = ..BitToDec(bitStr)
			
		#; UTF8,1字节 ASCII码
		} elseif ($e(highBit, 8, *) = "0") {
			s bitStr =  highBit
			s utf8num = ..BitToDec(bitStr)
		
		}
		s str = str _ $c(utf8num)
	}
	
	q str
}

通过该RAW2UTF8方法去解析直接的乱码。

注:这里直接通过%Stream.FileBinary方式去解析文件流,解析出来的是不包含编码格式,为二进制串。

ClassMethod TestRAW2UTF8(filename)
{
	s stream = ##class(%Stream.FileBinary).%New()
	s stream.Filename = filename
	s str = ..RAW2UTF8(stream)
	q str
}

通过该方法就可以解析出常见的UTF8乱码。

USER> w ##class(M.Code).TestRAW2UTF8("E:\m\code\utf8.txt")
《过零丁洋》宋朝·文天祥
 
辛苦遭逢起一经,干戈寥落四周星。
 
山河破碎风飘絮,身世浮沉雨打萍。
 
惶恐滩头说惶恐,零丁洋里叹零丁。
 
人生自古谁无死?留取丹心照汗青。
 

手写解析GB18030编码

首先创建一个GB18030编码格式的文件。之前已经验证ANSI能编码格式为GB18030编码格式

image

在编写解析GB18030编码之前,需要将码表导入到系统当中:

ClassMethod ImportGB1830Table(filename As %String) As %String
{
	s stream = ##class(%Stream.FileCharacter).%New()
	s stream.Filename = filename
	w stream.Size,!
	while 'stream.AtEnd {
		s str = stream.ReadLine()
		s char = $e(str, 2)
		s word = $replace($p(str, ",", 1), char, "")
		s gbkCode = $replace($p(str, ",", 2), char, "")
		s unicode = $replace($p(str, ",", 3), char, "")
		continue:(unicode = "")
		s ^GB18030(gbkCode) = word
	}
	q $$$OK
}
 w ##class(M.Code).ImportGB1830Table("E:\m\code\GB18030对照表.csv")

查看导入的码表Global

USER>zw ^GB18030
^GB18030(8140)="丂"
^GB18030(8141)="丄"
^GB18030(8142)="丅"
^GB18030(8143)="丆"
^GB18030(8144)="丏"
...
^GB18030(9481)="攣"
^GB18030(9482)="攤"
^GB18030(9483)="攦"
^GB18030(9484)="攧"
^GB18030(9485)="攨"
^GB18030(9486)="攩"
^GB18030(9487)="攪"

根据UTF8的编码规则编写如下RAW2UTF8方法。

方法逻辑如下:

  1. 读取1个首部字符判断UTF8所占字节大小。
  2. 如果高为0ASCII直接解析即可。
  3. 如果高为1直接根据对照码表直接解析即可。
ClassMethod RAW2GB18030(stream As %Stream.FileBinary) As %String
{
	s str= ""
	
	while 'stream.AtEnd {
		//s line = stream.Read(2)
		
		#; 读取1个首部字符判断UTF8所占字节大小
		s content = stream.Read(1)
		
		#; 获取该字符的2进制字符串
		s ascii = $a(content)
		s highBit = ..LogicalToDisplay(ascii)
		
		#; 长度小于8位,高位补0
		if ($l(highBit) < 8) {
			s highBit = highBit _ ..Repeat(0, 8 - $l(highBit))
		}
		if ($e(highBit, 8, *) = "0") {
			s bitStr =  highBit
			s ascii = ..BitToDec(bitStr)
			s char = $c(ascii)
		} else {
			s hex = ""
			s hex = hex _ $zhex($a(content))
			s content = stream.Read(1)
			s hex = hex _ $zhex($a(content))
			
			if ($d(^GB18030(hex))) {
				s char = $g(^GB18030(hex))
			}
		}
		
		s str = str _ char

		
	}
	q str
}

通过该RAW2GB18030方法去解析18030编码。

ClassMethod TestRAW2GB18030(filename)
{
	s stream = ##class(%Stream.FileBinary).%New()
	s stream.Filename = filename
	s str = ..RAW2GB18030(stream)
	q str
}
USER>w ##class(M.Code).TestRAW2GB18030("E:\m\code\gbk.txt")
《过零丁洋》宋朝·文天祥
 
辛苦遭逢起一经,干戈寥落四周星。
 
山河破碎风飘絮,身世浮沉雨打萍。
 
惶恐滩头说惶恐,零丁洋里叹零丁。
 
人生自古谁无死?留取丹心照汗青。

IRIS/Caché中哪些情况如要指定编码

  • 读取文件需要指定编码,示例如下:
    • s stream.TranslateTable = "UTF8"
ClassMethod UTF8(filename)
{
	s stream = ##class(%Stream.FileCharacter).%New()
	s stream.Filename = filename
	s stream.TranslateTable = "UTF8"
	w "字符长度:",stream.Size,!
	while 'stream.AtEnd {
		s line = stream.Read()
		w line,!
	}
	q $$$OK
}
  • 在读取HTTP请求时需要指定编码,示例如下:
    • s request.ContentCharset="UTF-8"
ClassMethod HttpGetDemo() As %String
{
	/* 定义request对象 */
	#dim request as %Net.HttpRequest= ##class(%Net.HttpRequest).%New()
	
	/* 请求地址不用加http:// */
	s request.Server = "192.168.1.21"
	//s request.ContentType
	/* Timeout指定等待web服务器响应的时间,以秒为单位。 缺省值是30秒。 */
	s request.Timeout = 5
	
	/* WriteTimeout指定等待Web服务器完成写入的时间(以秒为单位)。默认情况下,它将无限期等待。可接受的最小值为2秒。 */
	s request.WriteTimeout = 5
	
	#;指定编码
	s request.ContentCharset="UTF-8"
	
	/* 添加地址对象参数 */
	d request.InsertParam("CacheUserName", "yx")
	d request.InsertParam("CachePassword", "123456")
	d request.InsertParam("CacheNoRedirect", "1")
	d request.InsertParam("ClassName", "PHA.PCCP.MOB.API")
	d request.InsertParam("MethodName", "GetPhaWardRound")
	d request.InsertParam("params", "172#O")

	/* 设置cookies 防止占用多个lic */
	d:($g(%cookies) '= "") request.SetHeader("cookie", %cookies)
	
	/* 请求地址路径 */
	s status = request.Get("/dthealth/web/csp/pha.mob.broker.csp")
	
	if (status '= 1) {
		d $System.Status.DisplayError(status) 
		q "请求失败"
	}

	/* 定义response对象 */
	#dim response as %Net.HttpResponse  = request.HttpResponse
	
	/* 获取HTTP状态码 */
	s statusCode= response.StatusCode
	if (statusCode = 200){
		
		/* 获取头信息两种方式(一) */
		s encoding = response.GetHeader("CONTENT-ENCODING")

		/* 获取头信息两种方式(二) */
		s cookie = response.Headers("SET-COOKIE")
		s %cookies = $p(cookie, ";", 1)
		
		w "输出所有头部信息:",!
		d response.OutputHeaders()
		w !
		
		/* 获取流数据 */
		#dim stream as  %GlobalBinaryStream = response.Data
		s data = stream.Read()
	}

	q $g(data)
}
  • 读取xml时需要指定编码。
<?xml version='1.0' encoding='UTF-8'?>
  • HL7数据格式时需要指定编码。
Class IHE.Msg.MSH Extends (%Persistent, %JSON.Adaptor)
{

Property FieldSeparator(CAPTION = "字段分隔符") [ InitialExpression = "|", Required ];

Property EncodingCharacters(CAPTION = "编码字符") [ InitialExpression = "^~\&", Required ];

...

Property CharacterSet(CAPTION = "字符集") [ InitialExpression = "UTF-8" ];

}

image

获取系统默认的编码格式

USER>w $$GetPDefIO^%SYS.NLS(3)
GB18030

判断文件BOM的编码格式

BOM(Byte Order Mark),字节顺序标记,出现在文本文件头部,Unicode编码标准中用于标识文件是采用哪种格式的编码。

注:大多数文本文件都不含有BOM

  • 判断是否为UTF8BOM
ClassMethod IsUTF8BOM(filename As %String) As %Boolean
{
    s file = ##class(%FileBinaryStream).%New()
	s file.Filename = filename
	s bom = file.Read(3, .sc)
    if (bom = $c(239, 187, 191)) { 
        q $$$YES
    } 
    q $$$NO
}
  • 判断判断是否为GB18030BOM
ClassMethod IsGB18030BOM(filename As %String) As %Boolean
{
    s file = ##class(%FileBinaryStream).%New()
	s file.Filename = filename
	s bom = file.Read(4, .sc)
    if (bom = $c(132, 49, 149, 51)) {
		q $$$YES
    } 
    q $$$NO
}

  • 判断文件是否为UTF16BOM
ClassMethod IsUTF16BOM(filename As %String) As %Boolean
{
    s file = ##class(%FileBinaryStream).%New()
	s file.Filename = filename
	s bom = file.Read(2, .sc)
    if (bom =  $c(255, 254) || bom = $c(254, 255)) {
		q $$$YES
    } 
    q $$$NO
}
  • 判断文件是否有BOM
ClassMethod IsBOM(filename As %String) As %Boolean
{
	q:(..IsUTF8BOM(filename)) $$$YES
	q:(..IsUTF16BOM(filename)) $$$YES
	q:(..IsGB18030BOM(filename)) $$$YES
    q $$$NO
}

总结

  • 通过了解常见的编码格式与原理,可以在遇到乱码时,知道如何去处理。
  • 在国内环境中,使用手动解析UTF8GB18030两种解码方法,可以满足日常遇到的99%乱码问题。

以上是个人对常见编码的一些理解,由于个人能力有限,欢迎大家提出意见,共同交流。

0
0 488
文章 姚 鑫 · 七月 16, 2023 2m read

第六十章 开发Productions - ObjectScript Productions - 从管理门户进行测试 - 调试Production代码

调试Production代码

调试的第一步是启用跟踪,如监控生产中所述。如果这没有揭示问题,可以使用调试器单步调试代码,如下所示:

  1. IDE 中编辑代码以在要开始调试的位置插入 BREAK 命令。
  2. 为使用要调试的类的业务主机启用前台设置。
  3. 开始Production。在步骤 2 中标记的作业在终端的前台运行。
  4. 当到达该 BREAK 命令时,终端将进入调试模式,可以单步调试代码。

启用 %ETN 日志记录

事件日志自动包含有关系统级异常(包括代码中的异常)的部分信息。默认情况下,这些事件日志条目的结尾如下:

-- logged as '-' number - @' quit arg1/arg2 }'

要获得有关此类错误的更完整信息:

  1. 将 ^Ens.Debug("LogETN") 全局节点设置为任意值。

这会导致 IRIS 记录系统级异常的附加详细信息。

  1. 重新运行认为导致异常的代码(例如,重新发送消息)。
  2. 重新检查事件日志,它现在包含以下结尾的条目:
-- logged as '25 Sep 2012' number 15 @' quit arg1/arg2 }'

此信息引用应用程序错误日志中的一个条目,特别是引用 2012 年 9 月 25 日应用程序错误日志中的错误 15

  1. 然后要检查这些异常,可以:
  • 选择“系统操作 > 系统日志 > 应用程序错误日志”。
  • 使用 ^%ERN 例程。有关详细信息,请参阅使用 ObjectScript 中的其他调试工具。
0
0 66
文章 姚 鑫 · 七月 15, 2023 3m read

第五十九章 开发Productions - ObjectScript Productions - 测试和调试Production - 从管理门户进行测试

从管理门户进行测试

可以使用管理门户在开发、测试和调试Production时执行多项任务:

  • 能够查看和修改系统配置。
  • 能够启动和停止Production
  • 能够查看队列及其内容;消息及其详细信息;适配器和参与者及其状态;业务流程及其状态;配置项的代码和图形表示。
  • 能够查看、排序和有选择地清除事件日志条目。
  • 能够暂停(并稍后重新发送)连接暂时被阻止的消息。
  • 能够使用图形用户界面或通过输入 SQL SELECT 命令,按类别或消息内容过滤和搜索消息仓库中的特定消息。
  • 能够使用图形用户界面直观地跟踪消息活动。
  • 能够创建和查看统计报告。

对于开发人员来说,最有用的门户功能是不断收集运行时数据的监视服务、可用于向正在开发的产品发出模拟请求的测试服务以及记录业务主机发出的状态消息的事件日志。同时使用这些功能来生成测试数据并研究结果。

管理门户具有测试菜单,可以在其中测试业务主机和数据转换。它包含以下项目:

  • 业务主机-互操作性>测试>业务主机页面允许测试业务流程和业务操作。
  • 数据转换-此选项将带到另一个页面,可以在其中选择数据转换并单击测试。

使用测试服务

测试服务允许测试活动命名空间中正在运行的Production的业务流程或业务操作。

在测试业务流程或业务操作之前:

  • 确保相应的Production正在运行。
  • 确保为此Production启用了测试。在生产配置页面中
  1. 选择Production设置链接。
  2. Settings 选项卡上,打开 Development and Debugging 属性列表并选中 Testing Enabled 复选框。
  3. 选择应用。

可以从管理门户中的以下位置导航到测试服务:

  • 选择互操作性 > 测试,然后选择 Business HostsData Transformation
  • 从“生产配置”页面上的配置图中,在左窗格中选择业务流程或业务操作,然后在“操作”选项卡上选择“测试”。

要在业务流程或业务操作上使用测试服务:

  1. 在管理门户中,选择互操作性 > 测试 > 业务主机以显示测试服务页面。

此页面提供的选项允许选择业务流程或业务操作作为测试目标。

  1. 根据需要选择业务流程或业务操作。
  2. 从下拉列表中选择测试目标。
  3. 选择要发送的消息类型。该页面显示以下字段:
  • Current Production — 当前正在运行的Production的名称(仅供查看)。
  • Target目标 — 在之前的测试服务页面(仅查看)中选择的业务流程或业务操作。
  • Request Type请求类型 — 从请求消息列表中选择。仅列出对目标有效的请求类型,包括受支持类型的子类。
  1. 为选择的消息的属性输入值。

如果请求消息没有属性,则不显示任何属性。

如果正在测试虚拟文档消息,则有一个自由格式框,可以在其中粘贴测试消息内容。在此框下方,可以输入消息的对象属性。

  1. 选择调用以使用输入的值提交请求并查看结果。

如果在测试服务尝试请求时超时,等待页面将显示以下仅供查看的信息:

  • Target — 与请求关联的会话 ID
  • Request Type请求类型 — 所选目标的请求类型。
  • Session Id 会话 ID — 与请求关联的会话 ID
  • Request Sent——发送请求的日期和时间。
  • Response received 收到的响应 — 状态正在等待和图形进度条,表明工作正在完成。

最后,“结果”页面显示您的请求生成的响应中的所有输出值,包括带有完整错误消息文本的任何错误。

测试完成后,可以执行以下命令之一:

  • 选择完成返回主页。
  • 选择 Trace 以导航到 Visual Trace 页面,以直观地跟踪消息在整个生产过程中的路径。
0
0 98
文章 姚 鑫 · 七月 14, 2023 2m read

第五十八章 开发Productions - ObjectScript Productions - 测试和调试Production

本主题介绍可用于测试和调试产品的工具。该信息对于故障排除和调整企业已在使用的Production软件也很有用。

纠正Production问题状态

如果Production暂停或出现问题,请阅读本节。

暂停Production

Production在队列中的所有异步消息可以被处理之前停止时,就会发生暂停Production。如果不手动清除这些异步消息,它们会在Production开始备份时自动处理。如果希望处理消息,则在开始暂停Production之前不需要其他步骤。

恢复陷入困境的Production

如果 IRIS 停止但Production没有正常关闭,Production将获得故障状态。如果在没有先停止Production的情况下重新启动 IRIS 或重新启动机器,就会发生这种情况。

在这种情况下,“恢复”命令将显示在“Production配置”页面上。单击“恢复”关闭并清理有问题的Production实例,以便可以在准备好时运行新实例。

或者可能需要使用命令行来恢复Production。请参阅使用 Ens.Director 启动和停止Production

重置命名空间中的Production

在开发过程中,可能希望绝对确保一个Production的所有队列都已清除,或者在开始另一个Production之前删除有关Production的所有信息。 CleanProduction() 方法清除队列。

警告:切勿在实时部署的Production中使用此过程。 CleanProduction() 方法从队列中删除所有消息并删除有关Production的所有当前信息。仅在仍在开发的Production上使用此过程。

要使用 CleanProduction() 方法:

  1. 更改为适当的命名空间:
 set $namespace = "EnsSpace"

其中 EnsSpaceProduction运行的支持Production的命名空间的名称。

  1. 输入以下命令:
 do ##class(Ens.Director).CleanProduction()
0
0 86
文章 姚 鑫 · 七月 13, 2023 3m read

第五十七章 开发Productions - ObjectScript Productions - 不常见的任务 - 以编程方式使用查找表

IRIS 提供了名为 Lookup() 的实用函数,以便可以轻松地从业务规则或 DTL 数据转换中执行表查找。此功能仅在创建至少一个查找表并用适当的数据填充后才起作用。

有关定义查找表的信息,请参阅配置产品中的定义数据查找表。

如果需要比管理门户提供的更直接的查找表操作,请在类中使用 Ens.Util.LookupTable。此类公开查找表以通过对象或 SQL 进行访问。此外,它还提供类方法来清除表、将数据导出为 XML 以及从 XML 导入数据。

Ens.Util.LookupTable提供以下字符串属性:

TableName

查找表的名称,最多 255 个字符。可以通过在 IRIS 门户中选择“互操作性”、“配置”和“数据查找表”,然后选择“打开”来查看命名空间中定义的查找表。

KeyName

查找表中条目的键,最多 255 个字符。这是互操作性 > 配置 > 数据查找表页面上键字段的值。

DataValue

查找表中与此键关联的值,最多 32000 个字符。这是互操作性 > 配置 > 数据查找表页面上的值字段中的值。

示例 SQL 查询是:

SELECT KeyName,DataValue FROM Ens_Util.LookupTable WHERE TableName = 'myTab'

Ens.Util.LookupTable还提供了以下类方法:

%ClearTable()

删除指定查找表的内容。

  do ##class(Ens.Util.LookupTable).%ClearTable("myTab")

%Import()

从指定的 XML 文件导入查找表数据。要成功导入,文件必须使用与此类的 %Export() 方法提供的相同的 XML 格式。

  do ##class(Ens.Util.LookupTable).%Import("myFile.xml")

%Export()

将查找表数据导出到指定的 XML 文件。如果该文件存在, IRIS 会用新数据覆盖它。如果该文件尚不存在, IRIS 将创建它。以下示例仅导出指定查找表 myTab 的内容:

  do ##class(Ens.Util.LookupTable).%Export("myFile.xml","myTab")

以下示例导出命名空间中所有查找表的内容:

  do ##class(Ens.Util.LookupTable).%Export("myFile.xml")

生成的 XML 文件类似于以下示例。请注意,所有表中的所有条目都显示为单个 <lookupTable> 元素内的同级 <entry> 元素。

<?xml version="1.0"?>
<lookupTable>
  <entry table="myOtherTab" key="myKeyA">aaaaaa</entry>
  <entry table="myOtherTab" key="myKeyB">bbbbbbbbb</entry>
  <entry table="myTab" key="myKey1">1111</entry>
  <entry table="myTab" key="myKey2">22222</entry>
  <entry table="myTab" key="myKey3">333333</entry>
</lookupTable>

对于每个 <entry>,表属性标识包含该条目的表。 key 属性给出了键的名称。 <entry> 元素的文本内容提供条目的值。

除了上述 XML 格式之外,还可以使用 SQL 导入向导导入列出表和键的逗号分隔值 (CSV) 文件。

定义自定义存档管理器

对于 IRIS,管理门户提供了一个名为 Archive Manager 的工具;这在管理制作中进行了描述。可以定义和使用自定义存档管理器。为此,请创建一个类,如下所示:

  • 可以使用 Ens.Archive.Manager作为超类。
  • 它必须定义DoArchive()方法,该方法具有以下签名:
ClassMethod DoArchive() As %Status

另一种选择是使用企业消息库,它使能够存档来自多个产品的消息。有关概述,请参阅定义企业消息库。

0
0 77
文章 Michael Lei · 七月 13, 2023 1m read

前不久,北京市人民政府印发了《关于更好发挥数据要素作用进一步加快发展数字经济的实施意见》的通知。其中提到要“率先探索数据跨境流通”。今年1月,北京市互联网信息办公室也发文公示,首都医科大学附属北京友谊医院与荷兰阿姆斯特丹大学医学中心合作研究项目成为全国首个被北京网信办批准的数据出境安全评估案例(编号20220001)。可以预见,为更好发挥数据要素作用将来可能出现越来越多的跨境数据流通。那么我们今天仅仅看下,在医疗领域国际主要流行的数据标准都有哪些。

以下是国际数字医疗合作组织的主要统计(该组织协同了世界卫生组织WHO,OECD和33个不同的国家和地区)

从上表可以看出,数据共享领域 DICOM,HL7 v2, CDA, FHIR,v3 是主要的标准,在临床术语方面 ICD9/10/11, SNOMED 和Lionc是目前国际上各个国家和地区最主流的医疗数据标准。供大家参考。

相关阅读

FHIR标准和国际基于FHIR的互联互通实践

论集成标准的选择对医院信息集成平台建设的影响

对话:“数据二十条”与FHIR标准

原文链接:https://www.healthit.gov/topic/global-digital-health-partnership

0
0 434
文章 姚 鑫 · 七月 12, 2023 3m read

第五十六章 开发Productions - ObjectScript Productions - 不常见的任务 - 在适配器类中包含凭据

在适配器类中包含凭据

要在适配器类中包含生产凭证,请在类定义中执行以下操作:

  • 包括名为 Credentials 的设置。
  • 定义一个名为 CredentialsSet() 的方法,该方法使用 Credentials 设置的值作为键来查找 Credentials 表中的用户名和密码。然后实例化一个包含用户名和密码的凭据对象。

覆盖Production凭证

虽然Production凭证系统集中管理并将登录数据保留在源代码之外,但有时需要编写代码以从其他来源获取凭证。例如,代码可能会从 Web 表单或 cookie 中检索用户名和密码,然后将它们与 HTTP 出站适配器一起使用以连接到其他站点。

处理此问题的方法是在业务服务或业务操作代码中,在调用任何适配器方法之前执行以下两项操作:

  • 提供实例化凭证对象并向其分配用户名和密码值的代码
  • 请勿随后设置适配器 Credentials 属性或调用适配器 CredentialsSet() 方法,否则值可能会被重置。
  If ..Adapter.Credentials="" {
     Set ..Adapter.%CredentialsObj=##class(Ens.Config.Credentials).%New()
  }
  Set ..Adapter.%CredentialsObj.Username = tUsername
  Set ..Adapter.%CredentialsObj.Password = tPassword

此类代码提供了的 EnsLib.HTTP.OutboundAdapter 可以使用的凭据对象,但该对象内的值并非来自 Credentials 表。

覆盖启动和停止行为

IRIS 提供了一组回调方法,可以覆盖这些方法,以便在Production、其业务主机或其适配器的生命周期期间的开始和停止时间添加自定义处理。默认情况下,这些方法什么都不做。

Production类中的回调

如果有必须在Production开始前执行的代码,但需要 IRIS Production框架在其执行前运行,则必须覆盖Production类中的 OnStart() 方法。将这些代码语句放在 OnStart() 中,以便它们以正确的顺序执行:也就是说,在 IRIS 启动之后,但在Production开始接受请求之前。 OnStop() 方法还可用于在Production完成关闭之前执行一组任务。

Business Host 业务主机类中的回调

每个业务主机(业务服务、业务流程或业务操作)都是 Ens.Host的子类。在这些类中的任何一个中,都可以重写 OnProductionStart() 方法,以提供希望 IRISProduction启动时代表该主机执行的代码语句。还可以实现 OnProductionStop() 方法。

例如,如果Production需要对属性值进行不同的初始设置,请在业务操作的 OnInit() 方法中设置该值。例如,要将 LineTerminator 属性的初始设置更改为取决于操作系统:

 Method OnInit() As %Status
  {
      Set ..Adapter.LineTerminator="$Select($$$isUNIX:$C(10),1:$C(13,10))"
      Quit $$$OK
  }

适配器类中的回调

适配器类可以覆盖 OnInit() 方法。在创建适配器对象并设置其可配置属性值后调用此方法。 OnInit() 方法为适配器提供了一种执行任何特殊设置操作的方法。

例如,以下 OnInit() 方法在适配器启动时建立与设备的连接 — 假设该适配器还实现 ConnectToDevice() 方法:

Method OnInit() As %Status
{
  // Establish a connection to the input device
  Set tSC = ..ConnectToDevice()
  Quit tSC
}

适配器类还可以重写 OnTearDown() 方法。在适配器对象被销毁之前关闭期间调用此方法。 OnTearDown() 方法为适配器提供了一种执行任何特殊清理操作的方法。

例如,以下 OnTearDown() 方法会在适配器停止时关闭与设备的连接,假设此适配器还实现了名为 CloseDevice() 的方法:

Method OnTearDown() As %Status
{
  // close the input device
  Set tSC = ..CloseDevice()
  Quit tSC
}
0
0 80
文章 Kelly Huang · 七月 12, 2023 4m read

FHIR 通过提供标准化数据模型来构建医疗保健应用程序并促进不同医疗保健系统之间的数据交换,彻底改变了医疗保健行业。由于 FHIR 标准基于现代 API 驱动的方法,因此移动和 Web 开发人员更容易使用它。然而,与 FHIR API 交互仍然具有挑战性,尤其是在使用自然语言查询数据时。

隆重推出FHIR - AI 和 OpenAPI 链应用程序,该解决方案允许用户使用自然语言查询与 FHIR API 进行交互。该应用程序使用OpenAILangChainStreamlit构建,简化了查询 FHIR API 的过程并使其更加用户友好。

 

FHIR OpenAPI 规范是什么?

OpenAPI 规范(以前称为 Swagger,目前是OpenAPI Initiative的一部分)已成为软件开发领域的重要工具,使开发人员能够更有效地设计、记录 API 并与 API 交互。 OpenAPI 规范定义了一种标准的机器可读格式来描述 RESTful API,提供了一种清晰一致的方式来理解其功能并有效地使用它们。

在医疗保健领域,FHIR 成为数据交换和互操作性的领先标准。为了增强FHIR的互操作能力, HL7正式记录了FHIR OpenAPI规范,使开发人员能够将FHIR资源和操作无缝集成到他们的软件解决方案中。

 

FHIR OpenAPI 规范的优点:

0
0 395
文章 Lilian Huang · 七月 9, 2023 5m read

#Embedded Python #HL7 #InterSystems IRIS for Health

写在回复社区帖子《Python能否动态创建HL7消息》中。

前提条件和设置

使用一个启用了集成的命名空间。
注意:USER命名空间默认不启用互操作性。
如果以下建议创建一个新的互操作性命名空间来探索功能。

# 切换到
ZN "[互操作性名称空间名称]"

# 启动交互式Python shell:
Do $SYSTEM.Python.Shell()

启动脚本

#Load dependencies

import datetime as dt
import uuid

# Cache current time in CCYYMMDDHHMMss format
hl7_datetime_now=dt.datetime.now().strftime('%Y%m%d%H%M%S')

# Create HL7 Message
hl7=iris.cls("EnsLib.HL7.Message")._New()

# Set the doc type
# 2.5.1:ORU_R01 - Unsolicited transmission of an observation message
hl7.PokeDocType("2.5.1:ORU_R01")

这些信息的结构可以从管理门户中获取

0
0 294
文章 姚 鑫 · 七月 9, 2023 4m read

第五十三章 开发Productions - ObjectScript Productions - 不常见的任务 - 使用 Ens.Director 访问设置

使用 Ens.Director 访问设置

即使production未运行,类中的以下 Ens.Director 方法也允许检索生产设置:

GetAdapterSettings()

返回一个数组,其中包含所标识的配置项(业务服务或业务操作)的所有适配器设置的值。该数组由设置名称下标。可以使用 IRIS $ORDER 函数来访问数组的元素。此方法的第一个参数是一个字符串,其中包含由两个竖线 (||) 分隔的产品名称和配置项名称。返回值是状态值。如果状态值不是 $$$OK,则无法找到指定的生产名称 (myProd) 和配置项名称 (myOp) 组合。

 Set tSC=##class(Ens.Director).GetAdapterSettings("myProd||myOp",.tSettings)

GetAdapterSettingValue()

返回标识的配置项的命名适配器设置的值:业务服务或业务操作。第一个参数是一个字符串,其中包含由两个竖线 (||) 分隔的产品名称和配置项名称。第二个参数是配置设置的名称。第三个输出参数返回调用的状态值。例如:

 Set val=##class(Ens.Director).GetAdapterSettingValue("myProd||myOp","QSize",.tSC)

如果返回的状态值不是 $$$OK,则表示找不到指定的Productions 名称 (myProd) 和配置项名称 (myOp) 的组合,或者在配置中找不到指定名称 (QSize) 的设置那个指定的生产和配置项。

GetCurrProductionSettings()

返回一个数组,其中包含当前运行的Production或最近运行的Production的所有Production设置的值。该数组由设置名称下标。该方法的返回值是一个状态值。如果状态值不是 $$$OK,则无法识别当前Production

 Set tSC=##class(Ens.Director).GetCurrProductionSettings(.tSettings)

GetCurrProductionSettingValue()

从当前运行的Production或最近运行的Production返回指定Production设置的字符串值。第二个输出参数返回调用的状态值。如果此状态值不是 $$$OK,则在当前Production的配置中找不到指定名称的设置,或者无法识别当前Production

 Set myValue=##class(Ens.Director).GetCurrProductionSettingValue("mySet",.tSC)

GetHostSettings()

返回一个数组,其中包含所标识的配置项的所有设置值:业务服务、业务流程或业务操作。该数组由设置名称下标。此方法的第一个参数是一个字符串,其中包含由两个竖线 (||) 分隔的产品名称和配置项名称。返回值是状态值。如果状态值不是 $$$OK,则无法找到指定的Production名称 (myProd) 和配置项名称 (myOp) 组合。

 Set tSC=##class(Ens.Director).GetHostSettings("myProd||myOp",.tSettings)

GetHostSettingValue()

返回已识别配置项的命名设置值:业务服务、业务流程或业务操作。第一个参数是一个字符串,其中包含由两个竖线 (||) 分隔的Production名称和配置项名称。第二个参数是配置设置的名称。第三个输出参数返回调用的状态值。例如:

 Set val=##class(Ens.Director).GetHostSettingValue("myProd||myOp","QSize",.tSC)

如果返回的状态值不是 $$$OK,则表示找不到指定的Production名称 (myProd) 和配置项名称 (myOp) 的组合,或者在配置中找不到指定名称 (QSize) 的设置那个指定的Production和配置项。

GetProductionSettings()

返回一个数组,其中包含指定Production中所有Production设置的值。该数组由设置名称下标。该方法的返回值是一个状态值。如果状态值不是 $$$OK,则无法找到指定的Production

 Set tSC=##class(Ens.Director).GetProductionSettings("myProd",.tSettings)

GetProductionSettingValue()

从命名Production中返回命名Production设置的值。第三个输出参数返回调用的状态值。如果此状态值不是 $$$OK,则无法找到指定的Production,或者在指定Production的配置中找不到指定名称的设置。

 Set val=##class(Ens.Director).GetProductionSettingValue("prod","set",.tSC)

Ens.Director提供了许多类方法,包括许多仅供 IRIS 内部框架使用的方法。 建议仅使用本书中记录的 Ens.Director方法,并且仅按记录使用。

0
0 97
文章 姚 鑫 · 七月 7, 2023 3m read

第五十一章 开发Productions - ObjectScript Productions - 不常见的任务

定义自定义实用函数

IRIS提供了一组可以从业务规则和DTL中调用的实用函数;这些在开发业务规则的Productions中使用的效用函数中有所描述。可以添加自己的功能,业务规则引擎和业务规则编辑器会自动适应您的扩展。

要添加新的效用函数:

  1. 创建一个新类,它是 Ens.Rule.FunctionSet 的子类。此类不得扩展任何其他超类,只能扩展 Ens.Rule.FunctionSet
  2. 对于希望定义的每个函数,将一个类方法添加到新函数集类中。不支持多态性,所以准确的说,你必须把这些类方法标记为final。可以在现有的 Ens.Util.FunctionSet 方法中查看这个(Ens.Util.FunctionSetEns.Rule.FunctionSet的超类)。
  3. 编译新类。新函数现在可用于规则表达式。要调用这些函数,请使用子类中的 ClassMethod 名称。与 Ens.Rule.FunctionSet 中定义的函数不同,用户定义的方法名称必须使用它们所属的类进行完全限定。如果通过从管理门户中的向导中选择名称来添加它们,则会自动发生这种情况。

例如,以下函数集类提供了用于业务规则的日期和时间函数。它的类方法 DayOfWeek()TimeInSeconds() 调用 ObjectScript 函数 $ZDATE$PIECE 以从 ObjectScript 特殊变量 $HOROLOG 中提取所需的日期和时间值:

/// Time functions to use in rule definitions.
Class Demo.MsgRouter.Functions Extends Ens.Rule.FunctionSet
{

/// Returns the ordinal position of the day in the week,
/// where 0 is Sunday, 1 is Monday, and so on.
ClassMethod DayOfWeek() As %Integer [ CodeMode = expression, Final ]
{
$zd($H,10)
}

/// Returns the time as a number of seconds since midnight.
ClassMethod TimeInSeconds() As %Integer [ CodeMode = expression, Final ]
{
$p($H,",",2)
}

}

按照本主题中的描述添加新函数后,引用它的语法与内置函数略有不同。假设在一个继承自 Ens.Rule.FunctionSet 的类中定义此函数。

ClassMethod normalizaSexo(value as %String) as %String 

编译该类后,当使用 IRIS 互操作性可视化工具之一(例如路由规则编辑器或数据转换生成器)时,会看到函数名称 normalizaSexo 包含在函数选择框中以及内置函数,例如 StripIn , 包含等等。

假设从函数选择框中选择一个内置函数并查看生成的代码。会看到 IRIS 已经使用双点方法调用语法(在 DTL 中)生成了函数调用,或者只是通过名称引用了函数(在业务规则中)。 (这些语法规则在 Developing Business RulesUtility Functions for Use in Productions 中进行了解释。)

以下示例是来自 DTL<assign> 语句,它使用双点语法引用内置 Strip 函数:

<assign property='target.cod'
        value='..Strip(source.{PatientIDExternalID.ID},"<>CW")'
        action='set'/> 

但是,如果创建自己的用户定义函数,则 DTL 的语法会有所不同。仅仅识别功能是不够的;还必须确定包含函数的类方法的类的完整类名。假设函数 normalizaSexo 是在名为 HP.Util.funciones 的类中定义的。在这种情况下,从函数选择框中选择一个函数并查看生成的代码后,会看到类似于以下示例的内容:

<assign property='target.sexo'
        value='##class(HP.Util.funciones).normalizaSexo(source.{Sex})'
        action='set'/> 

如果希望将类似这样的语句直接键入到 DTL 代码中,而不是使用 Data Transformation Builder 生成代码,则需要注意这种语法变化。

0
0 112
文章 Jingwei Wang · 七月 7, 2023 2m read
    主机和备机为什么总是切换,会不会是与仲裁机连接的心跳检测出问题了

    查看镜像状态 打开管理门户 - ‘系统操作’ - ‘镜像监视器’
    如遇到主备切换,可以通过消息日志查看切换原因 打开管理门户 - ‘系统操作’ - ‘系统日志’ - ‘消息日志’      

    基础问题怎么查询

    通过管理门户查看日志 打开管理门户 - ‘系统操作’ - ‘系统日志’ - ‘消息日志’
    通过监控告警日志 告警日志文件:<intall-dir>/mgr/alerts.log文件      

    Production所有组件设置重试间隔、故障超时是什么意思

    重试间隔:与回复代码操作配合使用,当发生回复代码操作中设置的回复发生时,按照重试间隔设置的时间对外部业务系统再次访问。
    故障超时:发生故障时继续传递消息的总秒数,可以与回复代码操作配合使用。      

    有队列出现怎么办

    查看队列的方式 打开管理门户 - ‘Interoperability’ - ‘监视器’ - ‘队列’ 首先,查看队列计数是否是在降低,及时有队列,但是队列在正常下降,此状态为正常情况。 但是,如果队列持续升高,没有任何下降趋势,查看产生队列的相应组件的日志,查看是否是平台内部有异常出现。如果平台内部没有异常,查看第三方下游业务系统是否能正常通信。      

    如何设置重发

0
0 276
文章 Jingwei Wang · 七月 7, 2023 2m read

本篇文章主要介绍互联互通套件的一些基础问题:

  1. 基于互联互通套件通过互联互通成熟的测评的实施工作量
    • 电子病历共享文档部分:需要客户将业务系统数据灌入CCH套件SQL模型中
    • 服务部分:在平台做消息改造,或者直接做业务系统接口改造  
  2. 基于互联互通套件通过电子病例五级+互联互通成熟度测评四级需要的最低人员配备和项目总耗时
    • 需要了医院现有业务系统和人员配备,做进一步评估及分析  
  3. 目标只是通过互联互通成熟度测评需不需要FHIR
    • 不需要,如果只是过测评,只需要互联互通套件基础版就够了  
  4. BI相关功能如何实现
    • 可以使用DeepSee,基于Cubes做数据分析及钻取
  5. 如何使用Java进行快速开发
    • 可以使用PEX,支持Java开发,但是如果使用Production,推荐使用内置开发语言ObjectScript,学习成本更低,未来开发新特性能力更强大
  6. 有没有自带的ETL工具
    • InterSystems 互联互通套件中没有ETL工具,但是支持所有ETL工具的连接  
  7. 发送失败消息是否有记录
    • 所有错误消息都能够在平台监控到,且可以进行转发或者重发  
  8. 有没有按照单个服务流程进行整个业务流程的修改和查看
    • 平台内所有服务都可以按照类别区分,也可以按照服务查看业务流程,但是没有按照单个服务修改整个业务流程的界面
0
0 117
文章 姚 鑫 · 七月 6, 2023 3m read

第五十章 开发Productions - ObjectScript Productions - 高效处理批量记录

高效处理批量记录

RecordMap 功能一次导入一条记录,但如果正在导入或导出大量记录,则可以通过使用 RecordMap Batch 获得显着的效率提升。 RecordMap Batch 功能处理同类记录并一次处理一批中的所有记录。可以选择在批次之前加上一个标题记录,然后跟一个尾部记录。

要创建 RecordMap 批处理,需要实现一个继承自中的 %PersistentEnsLib.RecordMap.Batch的类。 Batch 类包含处理解析和写出与特定批次关联的任何标头和尾部的方法。必须提供解析和编写标头的代码。对于简单的表头和表尾,可以使用类中的 EnsLib.RecordMap.SimpleBatch,它继承自 Batch 类,并提供处理简单表头和表尾的代码。如果需要处理更复杂的标头和尾数据,可以扩展这两个批处理实现中的任何一个。

批处理遵循用于其他production消息格式(如 X12)的方法。这与处理 RecordMap 批处理对象的内置业务操作特别相关:这些业务操作接受 Batch 对象或扩展 EnsLib.RecordMap.BaseRecordMap 对象,或 BatchRolloverRequest 类型的请求。当接收到特定批次中的记录时,将打开批次并将批次标头写入临时文件,然后是该操作接收到的该批次中的对象。如果请求是同步的,类名、Id 和先前为该批次写入的记录数将在 EnsLib.RecordMap.BatchResponse中返回。批处理对象(可能是默认批处理)的接收将触发将批处理尾部写入临时文件,然后此文件将由适配器发送到所需的目的地以进行业务操作。如果一个 Batch 对象被自己接收,那么整个 Batch 将被写出到一个临时文件中,然后该文件将被传输到所需的位置。

重要提示:如果在此过程中启用了 ArchiveIO,则入站流的副本将保存在命名空间的临时流位置(默认位置为 <install-dir>/mgr/GLOBAL_DB_DIRECTORY/stream/)这些流将自动清除,不应手动删除。

批处理操作还支持默认批处理选项,借此将不属于某个批处理的记录添加到默认批处理中。可以通过将批处理对象发送到操作或将 BatchRolloverRequest 发送到操作来触发此批处理的输出。还可以将业务操作配置为对默认批次使用基于计划或基于计数的滚动更新。这些选项是在业务操作上配置的,可以同时使用。

服务选项主要涉及 Visual Trace 在批处理中显示消息的方式。

RecordMap Batch 操作在生成最终输出文件的过程中创建临时文件。可以通过指定 RecordMap Batch 操作的 IntermediateFilePath 设置来控制这些临时文件的位置。如果正在镜像命名空间的数据库,重要的是所有镜像成员都可以访问临时文件,以便在 RecordMap Batch 操作期间成功进行故障转移。

重要提示:RecordMap Batch 消息使用一对多关系来保存记录,这使得遍历所有记录并执行所需的转换变得非常容易。但是,该进程可能会消耗足够的内存,可能会收到 <STORE>错误。可能需要增加进程的内存,或者拆分输入文件,或者实现使用 SQL 而不是一对多关系的自定义转换。

0
0 91
文章 Michael Lei · 七月 4, 2023 11m read

这是个实验项目,使用OpenAI API与FHIR资源和Python相结合来回答医疗行业的用户提问。

项目想法

生成式人工智能,如OpenAI上提供的LLM模型, 已被证明在理解和回答高层次问题方面具有显著能力。他们使用大量的数据来训练他们的模型,因此他们可以回答复杂的问题。

他们甚至可以使用编程语言,根据提示创建代码 --我不得不承认,让我的工作自动化的想法让我感到有些焦虑。但到目前为止,似乎这是人们必须要习惯的事情,不管你喜不喜欢。所以我决定做一些尝试。

这个项目的主要想法是在我读到这篇文章关于ChatARKit项目时产生的。这个项目使用OpenAI的API来解释语音命令,在智能手机摄像头的实时视频中渲染3D物体--非常酷的项目。而且,这似乎是一个热门话题,因为我发现最近有一篇论文遵循类似的想法。

让我最担心的是使用ChatGPT对AR进行**编程。由于有一个开放的github repo,我搜索了一下,发现作者是如何使用ChatGPT生成代码的。这种技术被称为提示工程Prompt Engineering--这是维基百科关于它的文章,或者这两个更实用的参考资料: 12

所以我想--为什么不结合FHIR和Python试试类似的东西?以下是我的想法:

其主要构成是:

1
0 198
文章 姚 鑫 · 七月 5, 2023 3m read

第四十九章 开发Productions - ObjectScript Productions - 使用复杂记录映射器 - 复杂的记录映射类结构

复杂的记录映射类结构

有两个类以类似于描述记录映射的两个类的方式描述复杂的记录映射。描述复杂记录映射的两个类是:

  • 复杂记录映射,描述复杂记录的外部结构并实现复杂记录解析器和编写器。
  • 生成的复杂记录类定义了包含数据的对象的结构。该对象允许在数据转换和路由规则条件中引用数据。

一个复杂的记录映射业务服务读取并解析传入的数据并创建一条消息,该消息是生成的记录类的一个实例。业务流程可以读取、修改或生成生成的复杂记录类的实例。最后,复杂记录映射业务操作使用实例中的数据,使用复杂记录映射作为格式化模板写入输出数据。复杂记录映射类和生成的复杂记录类都具有描述数据的层次结构。复杂记录映射类和生成的复杂记录类具有并行结构。这与 RecordMap 类不同,其中生成的记录类可以具有不同的层次结构。

当创建一个新的复杂记录映射并将其保存在管理门户中时,此操作定义了一个类,用于在扩展 EnsLib.RecordMap.ComplexMap和在类中扩展 Ens.RequestO。为了定义生成的记录类,必须单击管理门户中的生成,这会调用 EnsLib.ComplexGenerator 类中的 Generate() 方法。仅编译 ComplexMap 类定义不会为生成的记录类创建代码。必须使用管理门户或从终端或代码调用 ComplexGenerator.Generate() 方法。生成的类中扩展 RecordMap.ComplexBatch 并在类中扩展 Ens.Request

ComplexMap 类在 XData 定义中定义了复杂的记录结构,该定义使用 RecordReference 元素指定的记录和 RecordSequence 元素定义的序列来定义 ComplexBatch。如果现有类的 RECORDMAPGENERATED 参数为 0,则目标类不会被复杂的记录映射框架修改——所有的更改都是生产开发人员的责任。

ComplexBatch 类具有对应于复杂映射定义中的以下顶级元素的属性:

  • 标头记录(如果指定)。此属性的类型设置为指定记录映射的生成记录类。
  • 将其类型设置为指定记录映射的生成记录类的记录,或者如果记录可以重复,则其类型设置为生成记录类的数组。
  • 其类型设置为为序列定义的类的序列,或者如果序列可以重复,则其类型设置为此类的数组。
  • Trailer record(如果指定)。此属性的类型设置为指定记录映射的生成记录类。

为每个序列定义一个类。序列类扩展了中的 ComplexSequence 和类中的 %XML.Adaptor。序列类在为 ComplexBatch 类定义的包和命名空间中定义。所有序列类都在该级别的命名空间中定义,即使它们包含在其他序列中也是如此。

每个序列都具有与其包含的记录和序列相对应的属性。

Production使用复杂的记录映射

要创建使用复杂记录的作品,可以执行以下操作:

  1. 为复杂记录的每个部分创建单独的记录映射,包括标题和结尾。有关如何创建单个记录映射的说明,请参阅使用记录映射器。请注意,如果打算使用样本文件,则应该创建一个样本文件,该文件仅包含在单个记录映射中定义的复杂记录的一部分。示例文件不应包含完整的复杂记录。
  2. 使用复杂记录映射器定义复杂记录的结构。
  3. 创建作品并添加一个或多个内置的复杂记录服务和操作。
  4. 如果产品只是将复杂的记录从一个应用程序传递到另一个应用程序,可以使用简单的路由引擎进程。但是,如果作品将一个复杂记录转换为另一个复杂记录,将在路由引擎中创建一个数据转换。如果输入和输出复杂记录具有相同的结构,可以创建连接源字段和目标字段的简单数据转换。例如,可以使用简单的数据转换将包含分隔记录的复杂记录转换为包含固定列记录的复杂记录。但是,如果输入复杂记录与输出复杂记录的结构不同,则必须在数据转换或业务流程语言 (BPL) 流程中添加代码。
0
0 113
文章 Tete Zhang · 七月 4, 2023 3m read

本文讨论了在使用或维护InterSystems产品中遇到问题时,试图确定问题时可能用到的思路和工具。

一般故障排除

确定问题发生的地点和时间

  • 问题是什么时候开始的?多久发生一次?
  • 问题首先出现在哪里?
  • 问题在什么条件下会被触发?

审查日志中的警告、错误和警报

以下日志可能包含有关该问题的有用信息。可以尝试在以下日志中寻找问题开始前后的警告或报错。

  • 检查 messages.log(IRIS)或者 cconsole.log(Caché and Ensemble)
    • 通过文件系统(<install-dir>/mgr/messages.log)访问messages.log文件,或者
    • 通过管理门户(系统操作>系统日志>Messages Log)访问文件内容
  • 检查production事件日志 (详细信息请参见文档
  • 查看应用程序错误日志 (详细信息请参见文档
  • 查看Web Gateway/CSP Gateway日志
  • 查看网络服务器(IIS/Apache)日志

检查实例是否可以访问足够的存储空间

  • 检查文件系统剩余空间(推荐设置操作系统层级的存储空间低告警)
  • 检查数据库剩余空间
    • 通过管理门户(系统操作>数据库>Freespace View)查看数据库文件内剩余空间百分比
  • 检查Journal日志空间

检查CPU活动

0
0 212
文章 姚 鑫 · 七月 1, 2023 4m read

第四十五章 开发Productions - ObjectScript Productions - 使用记录映射器 - 记录映射类结构

记录映射类结构

有两个类描述记录映射:

  • RecordMap 描述了记录的外部结构,实现了记录解析器和记录编写器。
  • 生成的记录类定义了包含数据的对象的结构。该对象允许在数据转换和路由规则条件中引用数据。

记录映射业务服务读取并解析传入数据并创建一条消息,该消息是生成的记录类的一个实例。业务流程可以读取、修改或生成生成的记录类的实例。最后,记录映射业务操作使用实例中的数据将 RecordMap 用作格式化模板来写入传出数据。 RecordMap 类和生成的记录类都具有描述数据的层次结构,但生成的对象结构不必与 RecordMap 结构相同。

当创建一个新的记录映射并将其保存在管理门户中时,此操作定义了一个扩展 RecordMap 类的类。为了定义生成的记录类,您必须在管理门户中单击“生成”,这会调用 EnsLib.RecordMap.Generator中的 GenerateObject()方法。仅编译 RecordMap 类定义不会为生成的记录类创建代码。必须使用管理门户或从终端或代码调用 Generator.GenerateObject() 方法。

RecordMap 由一系列字段和组合组成:

  • 字段定义具有指定类型的数据字段。字段类型可以指定参数,例如 VALUELISTMAXVALMAXLENFORMAT。在固定宽度的记录中,记录映射器使用字段宽度来设置 MAXVALMAXLEN 参数的默认值。
  • 组合由一系列字段和组合组成。组合可以嵌套在 RecordMap 中。

默认情况下,管理门户中的记录映射器使用复合级别来设置字段的限定名称。在分隔记录中,复合元素的嵌套级别决定了字段之间使用的分隔符,如下所示:

  1. RecordMap 中未包含在组合中的字段由第一个分隔符分隔。
  2. RecordMap 中的组合中出现的字段由第二个分隔符分隔。
  3. 出现在本身位于组合内的组合中的字段由第三个分隔符分隔。
  4. 每个额外的复合嵌套级别都会增加用于分隔字段的分隔符。

固定宽度记录中的组合提供有关数据结构的文档,但不影响 IRIS 处理消息的方式。

每个 RecordMap 对象都有对应的记录对象结构。当生成 RecordMap 时,Record Mapper 定义并编译一个记录对象,该对象定义记录映射的对象表示。默认情况下,管理门户中的 Record Mapper 将记录命名为 RecordMap 限定的“Record”,但可以在 Target Classname 字段中明确设置记录对象的名称。默认情况下,记录映射器通过使用包含它的组合限定名称来命名组合中的字段。如果使用默认限定名,记录对象类属性的结构将与 RecordMap 字段和组合的结构一致,但如果为字段分配其他名称,记录对象类属性的结构将不匹配RecordMap 字段和组合的结构。

记录对象类扩展了的 EnsLib.RecordMap.Base, %PersistentO, %XML.Adaptor, and Ens.Request。如果现有类的 RECORDMAPGENERATED 参数为 0,则目标类不会被记录映射框架修改——所有更改都由production开发人员负责。生成的记录类中的属性取决于记录映射中字段的名称。

记录对象类的属性对应于记录映射的字段,具有以下名称和类型:

  • 具有简单非限定名称的字段的名称出现在 RecordMap 或其中的组合中的任何位置。这些属性的类型由字段的类型决定。
  • 具有限定名称的字段的顶级名称出现在 RecordMap 或其中的组合中的任何位置。这些属性有一个对象类型和一个由共享相同顶级限定名的字段定义的类。这些类扩展了的 %SerialObject和类中的 %XML.Adaptor。这些类在生成的记录类名的范围内定义。这些类又具有对应于下一级名称限定的属性。

考虑一个示例,正在定义一个分隔记录映射,其中数据包含三个级别的分隔符,例如顶级分隔符字段分隔有关人员的信息,下一层分隔有关身份证号、姓名、和电话号码;最后一层分隔地址和名称中的元素。例如,消息可以以:

French Literature,TA,199-88-7777;Jones|Robert|Alfred;

要定义一个 RecordMap 来处理这些分隔符,需要在人员级别和姓名级别进行组合。因此 FamilyName 字段的默认字段名称可以是 Person.Name.FamilyName。此默认名称在记录对象类中创建了深层的类名,例如包含 NewRecordMap.Record.Person.Name.FamilyName 等属性的类 NewRecordMap.Record.Person.Name。可以通过在字段名称前加上 $(美元符号)字符来避免这种深层次的情况。如果这样做,类和属性都直接在记录范围内定义。使用相同的示例,ewRecordMap.Record.Name 类将包含 NewRecordMap.Record.FamilyName 等属性。

注意:用于限定字段名称的名称用于定义具有对象类型的属性。因此,不能使用名称既限定字段名称又作为字段名称的最后一部分,这将定义具有相同名称和数据类型的属性。

RecordMap 结构的对象模型

可以通过直接创建 XML 或使用 EnsLib.RecordMap.Model.* 类创建 RecordMap 的对象投影来实现类结构行为。一般来说,最受欢迎的方法是使用管理门户,但可能更喜欢使用对象模型来创建 RecordMap 结构。这些类的结构遵循 RecordMap 类结构;使用类参考以获取此级别的更多信息。

Production中使用记录映射

当在 Record Mapper 页面上选择生成对象类时,创建了一个可以在生产的业务服务中使用的类。

0
0 81