#ObjectScript

0 关注者 · 95 帖子

InterSystems ObjectScript 是一种脚本语言,可使用 InterSystems 数据平台的任何数据模型(对象、关系、键值、文档、全局变量/Global)处理数据,并在 InterSystems 数据平台上为服务器端应用程序开发业务逻辑。

文档

公告 Michael Lei · 一月 27, 2023

大家好,

我在 OEX 上加载了一个新软件包,我也计划在本月参加比赛。

简而言之,它为您提供以下内容。

  • 用于 InterSystems IRIS 的持久(表)类以保存记录历史的基类
  • 这些类允许在touch时将持久类记录历史化到另一个持久类中。
  • 这提供了任何记录的完整历史记录。
  • 它允许记录回滚到特定版本。
  • 它可以自动清除旧的历史记录。

请检查一下。

谢谢你们。

0
0 137
文章 Jingwei Wang · 一月 19, 2023 6m read

什么是网页抓取:

简单来说,网络抓取网络收获网络数据提取是从网站收集大数据(非结构化)的自动化过程。用户可以根据需要提取特定站点上的所有数据或特定数据。收集的数据可以以结构化格式存储以供进一步分析。

什么是网页抓取? — 詹姆斯·勒
网页抓取涉及的步骤:

  1. 找到您要抓取的网页的 URL
  2. 通过检查选择特定元素
  3. 编写代码获取被选元素的内容
  4. 以需要的格式存储数据

就这么简单!

用于网络抓取的流行库/工具是:

  • Selenium – 用于测试 Web 应用程序的框架
  • BeautifulSoup – 用于从 HTML、XML 和其他标记语言中获取数据的 Python 库
  • Pandas – 用于数据操作和分析的 Python 库


什么是Beautiful Soup?

Beautiful Soup 是一个纯 Python 库,用于从网站中提取结构化数据。它允许您解析来自 HTML 和 XML 文件的数据。它充当辅助模块,并以与使用其他可用开发人员工具以网页交互的方式与 HTML 交互。

0
0 296
文章 王喆 👀 · 十一月 17, 2022 5m read

       经过一段时间的学习和使用本文总结了一些使用VsCode开发的使用方法,本文偏向于应用但会对少量的我知晓的原理进行一部分解释。

参考教程链接:https://cn.community.intersystems.com/node/488611

VSCode下载:https://code.visualstudio.com/

  • 使用VSCode开发的优劣:

1 优势:

  1. 跨平台(Windows|MAC|Linux)开发调试远程服务端代码,而且可以快速导出COS代码(M语言也可以)。
  2. SQL辅助查询数据
  3. 快捷的代码调试方式,一种是直接在VSCode中调试,另一种是快速复制类名和方法名在Terminal中调试。
  4. 代码智能联想补全,类似其它语言,输入开头的前几个字符可以联想后面的。
  5. 快速跳转到方法定义(ctrl+鼠标左键 | F12)
  6. 主题图标多样化,可以使用默认的黑色,当然也可以使用和studio一样的样式,链接:https://cn.community.intersystems.com/node/516996

2 劣势:

  1. 无法导入导出XML文件
  2. 缺少一些Studio的常用功能:
    1. SOAP向导
    2. Java网关
    3. DT转换拖拽编写
    4. BP流程拖拽编写
  • 安装步骤

1官网安装Visual Studio Code编辑器

6
2 1152
文章 王喆 👀 · 九月 13, 2022 4m read

背景

作为集成平台厂商,在医院同其它系统联调的时候所做的事情中,多的不是开发代码而是查消息。我先演示一下目前我正在使用的IRIS查消息的方式:

例子1:

需要看【个人信息注册服务】

我只需要在框中输入【个人信息注册】回车

点击【查看消息】,显示的是消息里面的内容,如图所示:

点击【查看流程】,显示的是IRIS消息可视化的页面,如图所示:

例子2:

    需要查询患者ID为【2874621】这患者在集成平台调用了哪些服务

    我只需要选择下拉选择【患者ID】,然后输入【2874621】,回车

   

这个是我们以用户需求的角度直观的查询到指定的消息,IRIS也有这个功能—消息查看器,它是如何使用的呢?首先,我们得知道这条消息使用了哪些Production组件,其次我们需要了解这个消息使用的实体类的结构。比如同样查这个人的消息,我需要输入request.Body.PatientID=“2874621”,选择消息类。如果我需要查多个服务的我还需要多选消息类 …… 本文不是来介绍如何使用消息查看器的,各位大概知道就好。

程序分析与设计思路

    原始消息查看器的使用

我们先使用IRIS自带的【消息查看器】查患者ID为【2874621】个人信息注册服务,如图所示:

3
0 453
文章 王喆 👀 · 九月 7, 2022 4m read

前言

自接触IRIS以来在医院之中使用最多的是其作为一个ESB集成引擎来使用,作为医院的集成平台+数据中心中的一环。但是其也可以进行CRUD作为前后端分离项目的后端使用:

文章目录

前言

文章目录

一、开发技术和工具

二、开发路径和相关代码

       1.数据库

       2.准备工作

       3.开发接口的相关步骤

       4.成果展示

总结

本文章将以一个简单的页面展示IRIS的相关CRUD操作:

是的,我计划使用IRIS重构Production页面,先展示一下我开发完的成果吧:

呃の好像是一毛一样,哈哈

一、开发技术和工具

工欲善其事,比先利其器:

后端:HealthConnect+Global
前端:vue

使用IRIS%CSP.REST开发的Rest API接口,前端使用vue简单的把接口相关内容展示,可以编辑、新增组件,控制production启动、停止、更新检测状态。

二、开发路径和相关代码

1.数据库

首先,我们找到Production的相关表,分别是:Ens_Config.Item Ens_Config.Production 如图所示:

所以代码的思路很明确了对Ens_Config.Item进行新增、删除、修改、查询操作对Ens_Config.Production进行查询操作。

2.准备工作

在正式开发之前我们得先做一些准备工作:比如开放网关

7
6 625
文章 聆严 周 · 九月 27, 2022 6m read

背景

Cache起源于没有SQL的1970时代,当时各种高级计算机语言才刚刚诞生,其中M语言较为独特,它的诞生就是为了在没有操作系统的机器上,进行数据存储。别忘了,Unix在1971年才发布。M语言别具一格地采用了Global多维数组,统一了复杂的内存操作和文件读写,使之成为了1970年代数据库的事实标准,特别是在医疗行业。而后Intersystems在1978年接过M语言的旗帜,在M语言上添加了SQL兼容层和ObjectScript层,前者顺应了时代的潮流,后者不仅为M语言提供了强大的OOP和各种便捷的语法糖,还让数据能以对象形式进行访问,让数据和代码更加紧密。

本文将简述多维数组、SQL、对象这3种数据操作方式,提供实例代码片段,并在运行效率、开发效率、管理效率、实用性方面讨论它们的优缺点。 为方便讨论,以学校与学生为例。对每种操作方法,都列举3种典型的用例,分别为,访问某特定ID的学生(即数据库ID索引)、访问某特定studentID的学生(即遍历唯一索引)、和访问某学校的所有人(即遍历非唯一索引)。

现假设学生表/对象定义如下:

Class Student Extends %Persistent
{
Property schoolId AS  %String;
Property studentId As %String;
Property name As %String;

Index IdxOnSchoolId ON schoolId ;
Index IdxOnStudentId ON studentId [Unique];

Storage Default
{
<Data name="StudentDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>schoolId</Value>
</Value>
<Value name="3">
<Value>studentId</Value>
</Value>
<Value name="4">
<Value>name</Value>
</Value>
</Data>
<DataLocation>^StudentD</DataLocation>
<DefaultData>StudentDefaultData</DefaultData>
<IdLocation>^StudentD</IdLocation>
<IndexLocation>^StudentI</IndexLocation>
<StreamLocation>^StudentS</StreamLocation>
<Type>%Library.CacheStorage</Type>
}
}

方法1 多维数组

  • 例1. 访问某特定ID的学生
s id = 1 // 已知id
s student = ^StudentD(id)
s name = $LIST(student, 4)
w name
  • 例2. 访问某特定studentID的学生
s studentId = 1 // 已知studentId
s id = $ORDER(^StudentI("IdxOnStudentId",studentId,""))
s student = ^StudentD(id)
s name = $LIST(student, 4)
w name
  • 例3. 访问某学校的所有人
s schoolId = 1 // 已知schoolId
s id=""
for {
  s id = $ORDER(^StudentI("IdxOnSchoolId",schoolId,id))
  q:id=""

  s student = ^StudentD(id)
  s name = $LIST(student, 4)
  w name
}

$ORDER 方法返回多维数组最末端下标的下一个值。用来遍历多维数组。

方法2 SQL

  • 例1. 访问某特定ID的学生
s id = 1 // 已知id
&sql(SELECT name INTO :name from Student where id=:id)
w name
  • 例2. 访问某特定studentID的学生
s studentId = 1 // 已知studentId
&sql(SELECT name INTO :name from Student where studentId=:studentId)
w name
  • 例3. 访问某学校的所有人
s schoolId = 1 // 已知schoolId
s query="SELECT name from Student where schoolId=?"
s statement=##class(%SQL.Statement).%New()
s sc=statement.%Prepare(query)
s rset=statement.%Execute(schoolId)
while (rset.%Next()) {
    s name = rset.%Get("name")
    w name,!
}


  • &sql()为嵌入式SQL语句,在INTO子句中赋值给变量,适合单行查询。
  • &sql()也可以返回游标Cursor,以实现多多行查询,但效率比SQL.Statement低,不推荐使用。
  • SQL.Statement类实现动态SQL语句,动态查询适合返回多行结果。

方法3 对象

  • 例1. 访问某特定ID的学生
s id = 1 // 已知id
s student = ##class(Student).%OpenId(id)
s name = student.name
w name
  • 例2. 访问某特定studentID的学生
s studentId = 1 // 已知studentId
s student = ##class(Student).IdxOnStudentIdOpen(studentId)
s name = student.name
w name
  • 例3. 访问某学校的所有人
s schoolId = 1 // 已知schoolId
s id=""
for {
  s id = $ORDER(^StudentI("IdxOnSchoolId",schoolId,id))
  q:id=""

  s student = ##class(Student).%OpenId(id)
  s name = student.name
  w name
}
  • %OpenId方法通过ID查找并返回对象。
  • IndexOpen方法通过唯一索引值查找并返回对象。注意,非唯一索引没有类似方法。

讨论

  • 多维数组
    • 运行效率: 高。
      • 可控程度高,只要有老练的程序员,有足够的加班时间,有足够的资金和时间,总能打磨出最好的效率。据说多维数组的效率是SQL的10倍。
      • 面向过程编程,能够实现SQL难以实现的逻辑控制。
      • 注意,事实上,未经优化的多维数组操作未必比SQL效率高。
    • 开发效率: 低。
      • 虽然对于简单的数据操作,利用多维数组也能快速实现。但是一旦数组结构、索引、下标达到一定数量级,直接对为数组操作是个噩梦。代码中将充斥数组名,索引名,下标等magic values。
      • 直接操作数组太过底层,数据校验、初始值、空置、锁管理、事务等都需要人工编码。
    • 管理效率:低。
      • 值和索引必须同时维护,稍有不慎,容易造成索引损坏。
      • 不同熟练度的程序员实现可能千差万别,对锁的使用、回调函数的调用等容易产生分歧,统一化难度大。
      • 一旦数据定义发生变化,或者数据分布发生变化,需要调整或者调优,都需要较大人力投入。
      • 数据提取、数据迁移、数据备份等日常操作,都须要程序员参与。
    • 实用性:高
      • 对临时数据、不需要考虑数据提取的数据,多维数组是很好的Key-Value数据库。
  • SQL
    • 运行效率: 中。
      • SQL解析和优化需要耗费额外时间。
      • 适合批量处理。
      • 不适合面向过程的逻辑。
      • 可控程度低,如果不使用Frozen Plan,实际执行策略变化大,造成系统不稳定的假象。
      • 但是经过调优后的SQL,可以实现较好的执行效率。
    • 开发效率: 高。
      • SQL提供隔离等级、事务、锁表等指令,简化了并发。
      • SQL是声明式语言,简洁明了,可读性高,使程序员更关注结果,而不是遍历各种索引的过程。
    • 管理效率:高。
      • SQL提供了数据定义、数据查询、数据更新等的统一化。
      • 数据提取、数据迁移、数据备份可以通过标准SQL客户端。
      • 自适应性高,对存储的变化,例如变更索引,变更数据分布等,都能自动适应。
      • Intersystems为SQL提供了额外的权限配置。
    • 实用性:高
  • 对象
    • 运行效率: 低。
      • 不支持对索引的遍历,只能通过主索引和唯一索引访问单一对象。
    • 开发效率: 中。
      • 使对列的访问转化成了对对象属性的访问,使对外键的访问转化成了对外键对象的访问,代码的语义性强,可读性高。
    • 管理效率:中。
      • 在锁管理、值校验等方面统一化程度比多维数组高。
      • 和多维数组一样,也无法提供标准客户端来访问数据。
    • 实用性: 中
      • 实际应用中,持久类除了单个对象内字段的校验逻辑,几乎不包含业务逻辑。一是因为持久类必须稳定,一旦编译,要尽量避免再次编译。二是因为实际项目中,业务逻辑在业务层中,数据是相互依存的,例如退费数据需要退费审核,而这样的逻辑,不可能在某个数据对象中存在,只能在数据层之上的业务层才合理。

Do's & Don'ts

  • 批量的读写操作多用SQL。
  • 写操作应尽量用SQL或者对象。
  • 多维数组应尽量只用于读操作。
  • 多维数组的读、写操作应封装在方法中。
3
2 994
文章 王喆 👀 · 九月 18, 2022 4m read

       这是一篇笔记:

说明

       Restful是一种基于Http的网络应用程序的设计风格和开发方式,可以使用xml格式或者Json格式定义。

RESTFUL特点包括:

1、每一个URI代表1种资源;

2、客户端使用GETPOSTPUTDELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;

3、通过操作资源的表现形式来操作资源;

4、资源的表现形式是XML或者HTML

5、客户端与服务端之间的交互在请求之间是无状态的,从客户端到服务端的每个请求都必须包含理解请求所必需的信息。

IRIS中实现

GET

0
0 244
问题 tan jishan · 八月 3, 2022
我需要在当前命名空间下创建一系列的只读类,并限制除_system之外的所有用户都只有读取权限,无法在studio中编译,请问我应该如何操作呢?
我的目的是可以在工程的项目分支中管理这些类,并通过发布方式持续升级这部分类文件。
但是这些类的内部逻辑有可能会需要维护人员能够知晓其中的功能和实现方式,所以不能通过MakeDeployed来解决这个问题
我现在知道可以通过设置database的读写属性来解决这个问题,但是这样就需要额外新建一个database并maping到当前命名空间下。采取这种方式处理时有一个重大的缺点,即在执行代码发布过程中,需要停库,并且停库时间可能会在半个小时左右,这个我无法接受。
1
0 179
文章 Michael Lei · 八月 18, 2022 2m read

Hi 社区的朋友们,大家好!

有时我们需要以编程方式自动将CSV数据从文件或者UR网址L导入到InterSystems IRIS。我们希望创建具有适当数据类型的类并导入数据。

我在Open Exchange上发布了一个模块csvgen,它正是这样做的。

如果你只需要将CSV文件导入IRIS,你可以这么做:

USER>do ##class(community.csvgen).Generate("/usr/data/titanic.csv",,"Data.Titanic")

Class name: Data.Titanic
Header: PassengerId INTEGER,Survived INTEGER,Pclass INTEGER,Name VARCHAR(250),Sex VARCHAR(250),Age INTEGER,SibSp INTEGER,Parch INTEGER,Ticket VARCHAR(250),Fare MONEY,Cabin VARCHAR(250),Embarked VARCHAR(250)
Records imported: 891
USER>

或者你的CSV文件在互联网上, 例如GitHub上面的新冠疫情数据 你可以这样获得数据:

USER>d ##class(community.csvgen).GenerateFromURL("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_daily_reports/05-29-2020.csv",",","Data.Covid19")

Class name: Data.Covid19
Header: FIPS INTEGER,Admin2 VARCHAR(250),Province_State VARCHAR(250),Country_Region VARCHAR(250),Last_Update DATE,Lat MONEY,Long_ DOUBLE,Confirmed INTEGER,Deaths INTEGER,Recovered INTEGER,Active INTEGER,Combined_Key VARCHAR(250),Incidence_Rate DOUBLE,Case-Fatality_Ratio DOUBLE
Records imported: 3522
USER>
0
0 426
文章 Muhammad Waseem · 八月 11, 2022 2m read

嗨社区,

这篇文章公开介绍我的 iris-fhir-client 客户端应用。

 iris-fhir-client 可以可以借助嵌入式 python 连接到任何开放的 FHIR 服务器 fhirpy 图书馆.

通过终端和使用 CSP Web 应用程序获取资源信息。

0
0 200
文章 Michael Lei · 八月 9, 2022 23m read

在这篇文章中,你可以访问InterSystems开发者社区中与学习InterSystems IRIS最相关主题的文章库。找到按机器学习、嵌入式Python、JSON、API和REST应用、管理和配置InterSystems环境、Docker和云、VSCode、SQL、分析/BI、全局、安全、DevOps、互操作性、Native API排列的顶级发表的文章。快来享受学习的乐趣吧!

机器学习

机器学习是建立先进的数据分析和自动化人工活动的一种必要的技术,具有很好的效率。它可以创建认知模型,从现有的数据中学习,并根据其自我调整的算法进行预测、概率计算、分类、识别和 "非创造性 "的人类活动的自动化。

在所有情况下,InterSystems IRIS作为一个数据平台和环境来创建、执行、提供和使用这些机器学习模型。IRIS能够从SQL命令(IntegratedML)中使用ML,使用嵌入式Python和PMML(预测模型标记语言)来执行ML。你可以在以下文章中查看它的功能:

1
0 290
文章 Michael Lei · 八月 9, 2022 1m read

在Caché基础课程中,同学们同时学习了Caché开发和ObjectScript语法。为了帮助大家完成练习,我们提供了ObjectScript快速参考(俗称 "小抄")。

它不是所有ObjectScript的参考资料! 它是学生在课程中使用的ObjectScript命令和函数的列表,以及对象、集合等的常用语法。它还包含一些有用的宏。

我们正在为开发者社区提供一个pdf版本。

0
0 476
文章 Michael Lei · 八月 9, 2022 1m read

有时,有必要从主机操作系统的Shell(即你的ObjectScript程序所在的地方)执行命令,以启动程序、操作系统服务、安排crontasks以及其他活动。为此,该语言有一个叫做$ZF(-100). 的实用程序:

$ZF(-100,flags,program,args)

其中flags是你想执行的命令的类型。在我们的例子中,标志是"/ SHELL",用于在主机操作系统上执行shell命令。

Program是要执行的程序或服务的名称。

Args是传递给程序的执行参数。

一个例子是在提示符下打印一些内容,例如:

$ZF(-100,"/SHELL","echo","https://www.intersystems.com/")

如果你的程序依赖于改变当前目录,要运行该程序,在调用前使用以下命令:

Do ##class(%SYSTEM.Process).CurrentDirectory("/path/")
0
0 372
文章 Michael Lei · 八月 9, 2022 2m read

ObjectScriptt至少有三种处理错误的方法(状态代码status codes、异常 exceptions, SQLCODE等)。大多数系统代码使用状态码,但由于一些原因,异常更容易处理。在处理遗留代码时,你要花一些时间在不同的技术之间进行转换。我经常使用这些片段作为参考。希望它们对其他人也是有用的。

0
0 504
文章 Michael Lei · 六月 26, 2022 5m read

前一篇文章中,我已经演示了一种简单的方法来记录数据的变化。在这个时候,我改变了负责记录审计数据的 "审计抽象类 "和记录审计日志的数据结构。

我已经将数据结构改为父子结构,其中将有两个表来记录 "交易 "和在该交易中改变的 "字段的值"。

看一下新的数据模型:

看看从 "审计类 "改变的代码吧:

0
0 225
文章 Michael Lei · 六月 26, 2022 1m read

下面的代码允许用户查看其实例的审计设置。通过运行类方法 "test "来运行该代码。:


class objectscript.checkAudit Extends %RegisteredObject
{
	classmethod test() {
		w "Checking for Auditing...",!
		Set SYSOBJ = ##class(Security.System).%OpenId("SYSTEM")
		If +SYSOBJ = 0 Set SYSOBJ = ##class(Security.System).%New()
		i SYSOBJ.AuditEnabled {
			w "Security Auditing is enabled for the following services",!
			s rs=##class(%ResultSet).%New("Security.Events:ListAllSystem")
			s sc=rs.Execute()  If $$$ISERR(sc) Do DisplayError^%apiOBJ(sc) Quit
			while rs.%Next() {
                d:rs.Data("Enabled")="Yes" rs.%Print()
            }
            d rs.Close()
         
            s rs=##class(%ResultSet).%New("Security.Events:ListAllUser")
            s sc=rs.Execute()  If $$$ISERR(sc) Do DisplayError^%apiOBJ(sc) Quit
            while rs.%Next() {
                d:rs.Data("Enabled")="Yes" rs.%Print()
            }
            d rs.Close()
        }
    }
}	

这是 GitHub的链接: https://github.com/intersystems-community/code-snippets/blob/master/src/cls/objectscript/checkAudit.cls

0
0 111
文章 Frank Ma · 六月 13, 2022 2m read

这是一个在InterSystems IRIS中用python和objectscript建立的对比测试。

测试目的是比较在python和objectscript中从BP到BO来回发送一千条请求/消息的速度。

更多信息,请访问 https://github.com/LucasEnard/benchmark-python-objectscript

重要提示 : 这里用的是python, graph objectscipt和objectscript从一个BP到一个BO来回发送1000条消息的时间,单位是秒。

字符串信息是由十个字符串变量组成。

对象信息由十个对象变量组成,每个对象都是它自己的int、float、str和List(str)。

消息字符串1000条消息来回的时间 (秒)
Python BP1.8
BPL1.8
ObjectScript1.4
消息对象1000条消息来回的时间 (秒)
Python BP3.2
BPL2.1
ObjectScript1.8

行中函数的时间是列中函数的x倍 :

消息字符串PythonBPLObjectScript
Python111.3
BPL111.3
ObjectScript0.760.761

例如,第一行告诉我们,Python字符串的时间是Objectscript图形字符串函数的1倍,是Objectscript字符串函数的1.3倍。
( 利用第一个表格,我们可以验证我们的结果 :
1.3 * 1.4 = 1.8
1.3是第一行最后一列表格中的x,1.4s是本节第一个表格中看到的objectscript中的字符串信息的时间,1.8s实际上是python中的字符串信息的时间,我们可以通过寻找本节第一个表格或通过前面所示的微积分找到。)

行中的函数有列中函数X倍的时间:

Messages objectsPythonBPLObjectScript
Python11.51.8
BPL0.6611.2
ObjectScript0.550.831
0
0 127
文章 Michael Lei · 六月 7, 2022 3m read

我今天遇到了一个有趣的ObjectScript用例,有一个通用的解决方案,我想与大家分享。

用例:

我有一个JSON数组(在本例中具体而言是一个来自Jira的问题数组),我想在几个字段上进行聚合--例如,类别、优先级和问题类型。然后,我想把聚合的数据编平化到一个简单的列表中,其中包含每个组的总数。当然,对于聚合来说,使用一个本地数组的形式是有意义的,即:

agg(category, priority, type) = total

这样,对于输入数组中的每一条记录,我可以只用:

Do $increment(agg(category, priority, type))

但是一旦我做了聚合,我想把它变成一种更容易迭代的形式,比如一个整数下标的数组:

summary = n
summary(1) = $listbuild(total1, category1, priority1, type1)
...
summary(n) = $listbuild(totalN, categoryN, priorityN, typeN)

基础解决方案:

简单的方法是,用$Order嵌套三个For循环--比如说:

0
0 218
文章 Michael Lei · 六月 7, 2022 3m read

绕过ODBC使用ObjectScript访问远程系统

这是一个在 IRIS 2020.1 和 Caché 2018.1.3 上工作的代码示例
不会与新版本保持同步
也不会获得 InterSystems 提供的支持服务!   

我们经常会遇到这样的情况,由于各种原因ODBC是访问一个远程系统的唯一选择。如果你只需要检查或改变表,这就足够了。但你不能直接执行一些命令或改变一些Global。

特别感谢@Anna Golitsyna 启发我发表此文。

这个例子提供了3种 SQLprocedure 方法来实现访问远程系统这个目的,如果其他的访问方式被阻止,通常是被一些防火墙阻止。

0
0 148
文章 Jingwei Wang · 六月 6, 2022 2m read

Object Script(六)

ObjectScript中的变量是没有类型的,也就是说,它们没有一个指定的数据类型,可以接受任何数据值。

ObjectScript支持以下几种类型的变量:

1. 本地变量 :只有创建它的进程可以访问的变量,当该进程终止时,改变量将自动删除。一个本地变量可以从任何命名空间访问。

示例:

     SET str = "A string"

2. 进程私有的全局变量 : 只有创建它的进程可以访问的变量,并且在进程结束时不再存在。一个进程专用的全局变量可以从任何命名空间访问,因为它与命名空间无关。进程私有的全局变量对于临时存储大数据值特别有用。在许多情况下,它们可以替代Mgr/Temp目录的使用,在进程终止时提供自动清理。

示例:

       SET ^||flintstones(1)="Fred"

       SET ^||flintstones(2)="Wilma"

3. 全局变量 : 一个存储在InterSystems IRIS数据库中的持久性变量。一个全局变量可以从任何进程中访问,并且在创建它的进程终止后仍然存在。全局变量是针对个别命名空间的。

示例:

SET ^myglobal = "This is a global stored in the current namespace"

4. i%property实例变量

0
0 166
文章 Jingwei Wang · 六月 6, 2022 1m read

Object Script(五)

  • 在类中定义属性

Property PropName as Classname(PARAM1=value,PARAM2=value) [ Keywords ] ;
Property SSN As %String(PATTERN = "3N1""-""2N1""-""4N") [ Required ];

 

  • 创建函数示例

Studio创建:

将下段代码填写入建好的类中:

ClassMethod FindPatient(id As %String) As HIS.Patient{  Set patient= ##class(HIS.Patien).%OpenId(id)        Quit patient}

 

Terminal 调用:

set p = ##class(HIS.Patient).FindPatient(1)

 

  • 参数

传入参数的类型分为普通参数,输出型参数和返回参数:

普通参数 (传值参数):

Method Calculate(count As %Integer, name, state As %String = "CA") {…}

 

输出型参数(引用) :

0
0 233
文章 Michael Lei · 五月 23, 2022 1m read

大家是不是经常遇到以下情况:

  • 系统有 bug 但是无法在本地复现
  • 你需要在受影响的实例中运行几行代码
  • 能完整访问系统管理门户,但是没有终端或者管理控制台, 也不能访问 Studio, Atelier 或者 VSCode
  • 你要怎么运行你的几行代码来测试???
0
0 181
文章 Michael Lei · 五月 15, 2022 1m read

Hi, 社区!

想和大家分享一下俄罗斯论坛上的一个Debug方法。

假设我想对应用程序进行Debug,我想让它在某一行停止执行。

在代码中加入这一行:

l +d,-d

当我想在这一行中开始调试时,我在终端中屏蔽了d

USER> l +d

执行该应用程序。

应用程序在这一行停止,让我用Studio调试器连接到它。

为了释放锁,我在终端做了以下工作

USER> l -d

还有其他好的Debug 建议吗?

0
0 105
公告 Michael Lei · 五月 2, 2022

本月我们正式发布VS Code ObjectScript扩展的1.8.0版本,它包含以下增强功能和错误修复。

最大的更新是支持服务器端的项目文件,因为很多人会记得Studio。如果你在客户端工作,VS Code已经有很好的项目管理功能。你可以简单地使用一个文件夹作为一个项目,或者使用多个根目录的工作空间。但是如果你在服务器端工作,你可能会喜欢一些更好的工具管理能力,这就是这个功能的意义所在。更多内容,欢迎查阅文档的新项目章节

1.8.0版本的更新日志

  • 增强功能
    • 增加对服务器端项目的支持 (#851)
    • 实现isfs文件夹的重命名和删除 (#923, #922)
    • 支持isfs和导出过滤器的 "映射 "标志,以过滤从其他数据库映射的软件包(#931)

完整的更新日志在这里

如果您已经安装了ObjectScript扩展,VS Code会自动更新。如果您是一个新用户,请从这里开始。 

0
0 138
文章 Michael Lei · 四月 19, 2022 13m read

有很多方法可以使用Intersystems生成excel文件,其中一些是ZEN报告、IRIS报告(Logi报告或正式称为JReports),或者我们可以使用第三方Java库,可能性几乎是无限的。

但是,如果你想只用Caché ObjectScript创建一个简单的电子表格呢?(没有第三方应用程序)

在我的案例中,我需要生成包含大量原始数据的报告(财务人员喜欢这些数据),但是我的ZEN/IRIS失败了,给了我一个我想称之为 "零字节的文件",基本上说java的内存用完了,并导致报告服务器上的重载。

这可以用Office Open XML(OOXML)来完成。Office Open XML格式是由一个ZIP包内的一些XML文件组成的。因此,基本上我们需要生成这些XML文件,并将其压缩重命名为.xslx。就这么简单。

这些文件遵循一套简单的惯例,称为开放包装惯例。你需要声明各部分的内容类型,以及告诉消费应用程序应该从哪里开始。

为了创建一个简单的电子表格,我们至少需要5个文件。

  • workbook.xml
  • worksheet.xml
  • [Content_Types].xml
  • styles.xml
  • _rels
    • .rels
    • workbook.xml.rels
0
0 180
文章 Michael Lei · 四月 12, 2022 7m read

程序化访问 Production

要用程序编辑Production(界面),你可以使用互操作性API和SQL查询的组合。

现有的命名空间

从顶层了解你目前正在工作的命名空间和生产是很重要的。

// Object script 
// The active namespace is stored in this variable
$$$NAMESPACE 
// Print namespace
Write $$$NAMESPACE
# Python
import iris
# The active namespace is returned from this method
iris.utils._OriginalNamespace()
# Print namespace
print(iris.utils._OriginalNamespace())
>>> DEMONSTRATION

现有Production (正在或者最后一次运行的Production)

另外,知道你的Production名称是很重要的,你可以使用以下API获得名称空间中正在运行的Production。

// ObjectScript
USER>ZN "DEMONSTRATION"
// Get current or last run production
DEMONSTRATION>W ##class(Ens.Director).GetActiveProductionName()
>>> Hospital.HospitalProduction
#  Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris
active_production = iris.cls('Ens.Director').GetActiveProductionName()
print(active_production)
>>> Hospital.HospitalProduction

在production中寻找项目

你可以使用Objectscript或python来寻找Production中在运行的项目

1. SQL 查询 Production中的项目

SELECT Name FROM Ens_Config.Item Where Production = 'Hospital.HospitalProduction'
-- 
['From_Athena_Multi']
['From_Athena_Multi_Router']
['From_Cerner_ADT']
['From_Cerner_ADT_Router']
['From_Cerner_Orders']
['From_Cerner_Orders_Router']
['From_Dictaphone_Results']
['From_Dictaphone_Results_Router']
['From_Lab_Results']
['From_Lab_Results_Router']
['From_Radiology_Results']
['From_Radiology_Results_Router']
['HS.IHE.XDSb.DocumentSource.Operations']
['HS.IHE.XDSb.Repository.Operations']
['To_Cerner_Results']
['To_Dictaphone']
['To_Intellilab']
['To_Lab']
['To_Radiology']
-- 

2. SQL 查询Production中正在运行的项目

SELECT Name, ClassName 
FROM Ens_Config.Item 
WHERE Production = 'Hospital.HospitalProduction' 
  AND Enabled = 1

-- 
Name	                                ClassName
To_Radiology	                        EnsLib.HL7.Operation.FileOperation
To_Lab	                                EnsLib.HL7.Operation.FileOperation
To_Dictaphone	                        EnsLib.HL7.Operation.FileOperation
From_Cerner_ADT	                        EnsLib.HL7.Service.FileService
From_Cerner_ADT_Router	                EnsLib.HL7.MsgRouter.RoutingEngine
From_Radiology_Results_Router	        EnsLib.HL7.MsgRouter.RoutingEngine
From_Lab_Results_Router	                EnsLib.HL7.MsgRouter.RoutingEngine
From_Dictaphone_Results_Router	        EnsLib.HL7.MsgRouter.RoutingEngine
To_Intellilab	                        EnsLib.HL7.Operation.FileOperation
To_Cerner_Results	                    EnsLib.HL7.Operation.FileOperation
From_Cerner_Orders_Router	            EnsLib.HL7.MsgRouter.RoutingEngine
From_Athena_Multi_Router	            EnsLib.HL7.MsgRouter.RoutingEngine
HS.IHE.XDSb.DocumentSource.Operations	HS.IHE.XDSb.DocumentSource.Operations
-- 

3. 对象访问 Production 项目

// ObjectScript 
// Access to get all items in the active production
// Returns list of items
ClassMethod ListItemsInProduction()
{
    Set productionName =  ##class(Ens.Director).GetActiveProductionName()
    Set items = []
    &sql(Declare curr cursor FOR Select Name into :newId from Ens_Config.Item Where Production = :productionName)
    &sql(OPEN curr)
    For {
        &sql(FETCH curr)
        Quit:SQLCODE
        Do items.%Push(newId)
    }
    &sql(CLOSE curr)
    quit items
}

>>> zw ##class(ISC.SE.ProductionTools).ListItemsInProduction()

["From_Athena_Multi","From_Athena_Multi_Router","From_Cerner_ADT","From_Cerner_ADT_Router","From_Cerner_Orders","From_Cerner_Orders_Router","From_Dictaphone_Results","From_Dictaphone_Results_Router"
,"From_Lab_Results","From_Lab_Results_Router","From_Radiology_Results","From_Radiology_Results_Router","HS.IHE.XDSb.DocumentSource.Operations","HS.IHE.XDSb.Repository.Operations","To_Cerner_Results"
,"To_Dictaphone","To_Intellilab","To_Lab","To_Radiology"]  ; <DYNAMIC ARRAY>
# Python
# Get Dataframe of active production items

import os
# Set environment variables
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris

def getActiveProductionItems():
    productionName = iris.cls('Ens.Director').GetActiveProductionName()
    df = iris.sql.exec("SELECT Name FROM Ens_Config.Item Where Production = '{}'".format(productionName))
    return df

production_items_df = getActiveProductionItems().dataframe()

#                                      name
# 0                       From_Athena_Multi
# 1                From_Athena_Multi_Router
# 2                         From_Cerner_ADT
# 3                  From_Cerner_ADT_Router
# 4                      From_Cerner_Orders
# 5               From_Cerner_Orders_Router
# 6                 From_Dictaphone_Results
# 7          From_Dictaphone_Results_Router
# 8                        From_Lab_Results
# 9                 From_Lab_Results_Router
# 10                 From_Radiology_Results
# 11          From_Radiology_Results_Router
# 12  HS.IHE.XDSb.DocumentSource.Operations
# 13      HS.IHE.XDSb.Repository.Operations
# 14                      To_Cerner_Results
# 15                          To_Dictaphone
# 16                          To_Intellilab
# 17                                 To_Lab
# 18                           To_Radiology

通过 API操作Production

1. 增加组件

// ObjectScript
set productionName = ##class(Ens.Director).GetActiveProductionName()
//create a new xml file service
set classname="EnsLib.XML.FileService"	//class of this item
set name="NewService"			//config name
set item=##class(Ens.Config.Item).%New(classname)

set item.Name=name
set item.Comment = "Test Service"
set item.PoolSize = "1"
set item.Enabled = 1
do item.%Save()
//	
// open the production class
// set prod="Test.configtest"	//production name set manually
// OR
set prod = productionName
set prodObj=##class(Ens.Config.Production).%OpenId(prod)
//save the new item
set tSC=prodObj.Items.Insert(item)
set tSC=prodObj.SaveToClass(item)
set tSC=prodObj.%Save()

// DELETE item from above
set tSC = prodObj.RemoveItem(item)
set tSC = prodObj.SaveToClass()
set tSC=prodObj.%Save()
# Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris
active_production = iris.cls('Ens.Director').GetActiveProductionName()
print("Current Production {}".format(active_production))

# Metadata about component
classname="EnsLib.XML.FileService"	 # class of this item
name="NewService"			         # config name
item=iris.cls('Ens.Config.Item')._New(classname) # Make new component
item.Name=name
item.Comment = "Test Service"
item.PoolSize = "1"
item.Enabled = 1
item._Save()

# open the production class
# prod="Test.configtest"	# production name manually set
# OR use the active production from above
prod = active_production

prodObj=iris.cls('Ens.Config.Production')._OpenId(prod)
# save the production after we insert that item to it
tSC=prodObj.Items.Insert(item)
tSC=prodObj.SaveToClass(item)
tSC=prodObj._Save()

# DELETE item from above
tSC = prodObj.RemoveItem(item)
tSC = prodObj.SaveToClass()
tSC=prodObj._Save()

2. 激活 / 关闭 组件

// ObjectScript
set productionName = ##class(Ens.Director).GetActiveProductionName()
set itemName = "My.Inbound.HL7"
// Required for Enable Item
Set componentName = productionName _ "||" _ itemName _ "|"
// Disable or enable
Set enable = 1 // or 0
Do ##class(Ens.Director).EnableConfigItem(componentName, enable, 1)

/// Enable or disable a ConfigItem in a Production. The Production may be running or not.
/// The pConfigItemName argument gives the name of the config item to be enabled or disabled
/// In the case of multiple matching items with the same config name, if any is already enabled then
///  the pEnable=1 option will do nothing and the pEnable=0 option will disable the running matching
///   production item, or if not running then the first matching enabled item that it finds.
///   
/// See method Ens.Director.ParseConfigName() for full syntax of the ConfigItem name specification string.
ClassMethod EnableConfigItem(pConfigItemName As %String, pEnable As %Boolean = 1, pDoUpdate As %Boolean = 1)
# Python
import os
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'
import iris

active_production = iris.cls('Ens.Director').GetActiveProductionName()
item_name = "My.Inbound.HL7"
componentName = active_production + "||" + item_name + "|"

enable = 1 # or 0
iris.cls('Ens.Director').EnableConfigItem(componentName, enable, 1)

通过API获得Production状态

// ObjectScript
/// This method returns the production status via the output parameters.
/// pProductionName: Returns the production name when the status is running, suspended or troubled.
/// pState: Outputs production status. The valid values are:
///          $$$eProductionStateRunning == 1
///          $$$eProductionStateStopped == 2
///          $$$eProductionStateSuspended == 3
///          $$$eProductionStateTroubled == 4
Set sc = ##class(Ens.Director).GetProductionStatus(.productionName, .productionState) 
Write productionName, " -- ", productionState
import os
# Set namespace the hard way
os.environ['IRISNAMESPACE'] = 'DEMONSTRATION'

import iris

# TEST 2 with output variables
productionName, productionState = iris.ref('productionName'), iris.ref('productionState')
status = iris.cls('Ens.Director').GetProductionStatus(productionName, productionState) 

print("Status: {}".format(status))
# see .value
print("Production: {}".format(productionName.value))
# see .value
print("Production State: {}".format(productionState.value))
0
0 341
公告 Jeff Liu · 三月 30, 2022

HI 开发者们,

我们在bilibili 发布了新的视频!

<iframe src="//player.bilibili.com/player.html?aid=637281555&bvid=BV1cb4y1p7RE&cid=550213579&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>

看看VS Code的InterSystems ObjectScript的调试器如何帮助你浏览和检查代码。了解如何为调试类方法和production组件编写启动配置,并获得VS Code调试器界面的概述--包括变量部分、观察窗格和调试控制台。

请欣赏并继续关注!

1
0 206