搜索​​​​

清除过滤器
文章
Frank Ma · 三月 2, 2022

密码有多安全?

如何检查密码是否足够强大,使其不会很快被破解? 又如何制作一个强大的密码? 我开发了一个工具,可能对这个问题有帮助。你可以在OpenExchange上找到它。用zpm安装。 zpm "install passwords-tool" 这个模块将只安装一个类 caretdev.Passwords中,其中包含一些有用的方法。 安全密码 要获得一个安全的密码,通常只需使用大写和小写的字母、数字和特殊符号,而且至少要有8个符号的长度。 Generate方法使用的参数: Length - 只是一个生成密码的长度,默认值为12。 IncludeUpperLetter - 包括大写的ASCII字母,如果需要的话是2,默认是1。 IncludeLowerLetter - 包括小写ASCII字母,如果需要的话,默认为2。 IncludeNumber - 包括数字,如果需要的话,2个,默认为1个。 IncludeSymbol - 包括特殊符号,如果需要的话,2个,默认为1个。 USER>w ##class(caretdev.Passwords).Generate(12,1,0,0,0) FMXRQEQPOVBC USER>w ##class(caretdev.Passwords).Generate(12,1,1,0,0) rgbPyWApcUjp USER>w ##class(caretdev.Passwords).Generate(12,1,1,1,0) cDuLf8FqEDx7 USER>w ##class(caretdev.Passwords).Generate(12,1,1,1,1) 0J/ lLbW|T$ USER>w ##class(caretdev.Passwords).Generate() w3}{OQA|T{h^ 这个方法使用$System.Encryption.GenCryptRand(),而不是普通的$random,后者对于密码来说可能不是那么安全。除了获得最佳密码外,它还在一个循环中生成一些密码,检查密码熵的值,并返回一个最高分。 密码熵 Entropy 密码熵预测了一个给定的密码通过猜测、暴力破解、字典攻击或其他常见方法破解的难度。熵本质上是衡量攻击者需要进行多少次猜测才能猜出你的密码。有几种方法来计算它。 USER>write ##class(caretdev.Passwords).Entropy("Pas$W0rD") 52.56 熵值公式L = 密码长度;密码中的符号数S = 独特的可能符号库的大小(字符集)。 比如: 数字(0-9): 10小写拉丁字母(a-z): 26小写和大写拉丁字母(a-z,A-Z):52ASCII可打印字符集(a-z、A-Z、符号、空格):95 可能的组合数=S**L密码熵值 = log2(可能的组合数) 香农熵 Shannon Entropy USER>write ##class(caretdev.Passwords).ShannonScore("Pas$W0rD") 24 这种方式是基于使用字符的频率,以及密码的整个长度。详情见 Wiki. NIST得分 USER>write ##class(caretdev.Passwords).NISTScore("Pas$W0rD") 24 计算 第一个字符的熵是4比特; 接下来的七个字符的熵是每个字符2比特; 第九个到第二十个字符的熵为每字符1.5比特; 第21个及以上的字符,每个字符有1比特的熵; 如果同时使用大写字母和非字母字符,将增加6位的 "奖励"; 对于长度为1到19个字符的密码,在进行广泛的字典检查后,会增加6位的 "奖励",以确保密码不包含在一个大的字典中。20个字符以上的密码不会得到这个奖励,因为它被认为是由多个字典词组成的密码。 强度 Strength write ##class(caretdev.Passwords).DetermineStrength("Pas$W0rD") REASONABLE 生成的密码 USER>write ##class(caretdev.Passwords).DetermineStrength(##class(caretdev.Passwords).Generate()) STRONG 非常弱 VERY_WEAK - 熵值Entropy <= 32 弱WEAK - 熵值Entropy <= 48 正常 REASONABLE - 熵值Entropy <= 64 强 STRONG - 熵值Entropy <= 80 非常强 VERY_STRONG - 熵值Entropy > 80 如果你喜欢这篇文章,请投票 。
文章
姚 鑫 · 三月 7, 2022

第七十四章 SQL函数 LEAST

# 第七十四章 SQL函数 LEAST 从一系列表达式中返回最小值的函数。 # 大纲 ``` LEAST(expression,expression[,...]) ``` # 参数 - `expression` - 解析为数字或字符串的表达式。 将这些表达式的值相互比较,并返回最小值。 表达式可以是字段名、文字、算术表达式、主机变量或对象引用。 最多可以列出`140`个逗号分隔的表达式。 # 描述 `LEAST`从逗号分隔的表达式序列中返回最小值。 表达式按从左到右的顺序求值。 如果只提供一个表达式,则`LEAST`返回该值。 如果任何表达式为`NULL`, `LEAST`返回`NULL`。 如果所有表达式值都解析为规范数,则按数值顺序对它们进行比较。 如果引用的字符串包含规范格式的数字,则按数字顺序对其进行比较。 但是,如果引用的字符串包含非规范格式的数字(例如,`'00'`、`'0.4'`或`'+4'`),则将其作为字符串进行比较。 字符串比较按排序顺序逐字符执行。 任何字符串值都大于任何数字值。 空字符串大于任何数字值,但小于任何其他字符串值。 如果返回值是一个数字,`LEAST`将以规范格式返回它(删除前导和末尾的零,等等)。 如果返回值是一个字符串,`LEAST`将不改变返回值,包括任何开头或结尾的空格。 `LEAST`返回逗号分隔的一系列表达式中的最小值。 `GREATEST`返回逗号分隔的一系列表达式中的最大值。 `COALESCE`返回逗号分隔的一系列表达式中的第一个非`null`值。 # 返回值数据类型 如果表达式值的数据类型不同,则返回的数据类型是与所有可能的返回值最兼容的类型,具有最高数据类型优先级的数据类型。 例如,如果一个表达式是整数,而另一个表达式是小数,则`LEAST`返回数据类型`NUMERIC`的值。 这是因为`NUMERIC`是具有最高优先级的数据类型,并且与两者兼容。 但是,如果表达式是文字数字或字符串,则`LEAST`返回数据类型`VARCHAR`。 # 示例 在下面的例子中,每个`LEAST`比较三个正则数: ```sql SELECT LEAST(22,2.2,-21) AS HighNum, LEAST('2.2','22','-21') AS HighNumStr -21 -21 ``` 在下面的例子中,每个`LEAST`比较三个数字字符串。 然而,每个`LEAST`包含一个非规范字符串; 这些非规范值将作为字符串进行比较。 字符串总是大于数字: ```sql SELECT LEAST('22','+2.2','21'), LEAST('0.2','22','21') 21 21 ``` 在下面的例子中,每个`LEAST`都会比较三个字符串,并返回排序序列最低的值: ```sql SELECT LEAST('A','a',''), LEAST('a','aa','abc'), LEAST('#','0','7'), LEAST('##','00','77') a 0 77 ``` 下面的例子比较了两个被视为标准数字的日期:作为`$HOROLOG`整数的出生日期和转换为日期的`58074`整数。 它返回每个在`20`世纪出生的人的出生日期。 任何在`1999年12月31日`之后出生的人都会显示默认的出生日期为`2000年1月1日`: ```sql SELECT Name,LEAST(DOB,TO_DATE(58074)) AS NewMillenium FROM Sample.Person ``` ![image](792AA862F12A475B820DEF99233715EA)
公告
Michael Lei · 八月 13, 2022

[视频] 机器学习201--神经网络和图像识别

嗨,开发者们。 不要错过这个由InterSystems Healthcare副总裁@Donald.Woodlock主持的动手实践环节: ⏯ Machine Learning 201 - Neural Networks and Image Recognition 观看如何训练机器学习模型来做图像分类。几十年来,机器学习试图解决的最初的经典问题之一是如何在图片中区分狗和猫--这甚至是一个小孩子都能做到的事,但计算机却发现它非常困难。几十年后,这个问题被解决了,并为机器学习现在善于阅读放射学图像、识别人脸、为自动驾驶汽车识别物体类型、从卫星图像识别森林砍伐以及其他各种用例铺平了道路。我们将在这个实践环节中学习如何做到这一点。特别是,我们将解决识别手写数字的问题。我们将陆续建立更复杂的模型来提高这项任务的准确性,包括逻辑回归、前馈神经网络和卷积神经网络。 这是一个2小时的会议,通过虚拟会议的方式现场录制,有一些与会者参加。不要求有机器学习或python的经验,但最好不要讨厌编程。 你将需要一个Kaggle账户(http://www.kaggle.com)来跟上这个视频。该账户需要经过 "手机验证",以便使用Kaggle的GPU功能,这是其中一个练习所需要的。 作为本课的一部分,你将需要的链接是:https://www.kaggle.com/competitions/digit-recognizer笔记本的链接是:http://www.donwoodlock.com/ml201/25Jul2022/index.html 祝您愉快,敬请期待!
问题
sun yao · 十二月 27, 2022

能否从BP流程中提取出switch分支相关内容,通过解析代码或查看源表等相关操作?

如下图,系统表或代码中是否有相关方法可直接解析BP中的swith分支内容,实现接口的自动统计相关功能另:当前版本是否有已封装的页面,方便用户操作查看消息等功能 您好,对于BPL中的成分,由于其在代码中以XML记录,可以通过解析该类中xdata中的xml代码段,基于xml文本提取出switch标签中的内容进行解析可以获得其中的内容,可参考https://docs.intersystems.com/irisforhealth20222/csp/docbook/Doc.View.cls?KEY=GOBJ_xdata 但需要理解的是,基于静态代码分析得到的结果是理论上的分支,不一定能代表实际的业务运行情况,例如在代码有bug导致分支无效的情况等。而所有流经IRIS的消息都被持久化在消息标中,基于消息表通过SQL进行统计更能反映实际的业务运行状况。可参考:https://cn.community.intersystems.com/post/intersystems-%E6%95%B0%E6%8D%AE%E5%B9%B3%E5%8F%B0%E4%BA%92%E6%93%8D%E4%BD%9C%E5%8A%9F%E8%83%BD%E8%BF%90%E8%A1%8C%E7%BB%B4%E6%8A%A4%E7%AE%A1%E7%90%86%E5%9F%BA%E7%A1%80-%E4%BA%92%E6%93%8D%E4%BD%9C%E6%B6%88%E6%81%AF%E7%AE%A1%E7%90%86https://cn.community.intersystems.com/post/%E9%9B%86%E6%88%90%E4%BA%A7%E5%93%81%E7%9A%84%E4%B8%9A%E5%8A%A1%E8%A1%8C%E4%B8%BA%E7%9B%91%E6%8E%A7 另外,IRIS所有产品都带有查看消息的web界面,可以从portal中访问,也可以作为一个url被集成到用户自己的应用中去:
文章
Frank Ma · 六月 13, 2022

Python和ObjectsScript中消息响应时间的对比测试

这是一个在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 BP | 1.8 | | BPL | 1.8 | | ObjectScript | 1.4 | | 消息对象| 1000条消息来回的时间 (秒) | |------------------------|------------------| | Python BP | 3.2 | | BPL | 2.1 | | ObjectScript | 1.8 | 行中函数的时间是列中函数的x倍 : | 消息字符串| Python | BPL | ObjectScript | |------------------------|------------|------------------------|------------------| | Python | 1 | 1 | 1.3 | | BPL | 1 | 1 | 1.3 | | ObjectScript | 0.76 | 0.76 | 1 | 例如,第一行告诉我们,Python字符串的时间是Objectscript图形字符串函数的1倍,是Objectscript字符串函数的1.3倍。 ( 利用第一个表格,我们可以验证我们的结果 : 1.3 * 1.4 = 1.8 1.3是第一行最后一列表格中的x,1.4s是本节第一个表格中看到的objectscript中的字符串信息的时间,1.8s实际上是python中的字符串信息的时间,我们可以通过寻找本节第一个表格或通过前面所示的微积分找到。) 行中的函数有列中函数X倍的时间: | Messages objects| Python | BPL | ObjectScript | |------------------------|------------|------------------------|------------------| | Python | 1 | 1.5 | 1.8 | | BPL | 0.66 | 1 | 1.2 | | ObjectScript | 0.55 | 0.83 | 1 |
文章
Jingwei Wang · 十二月 30, 2021

用API描述文件创建REST服务

可以使用内嵌REST API用描述文件生成REST服务 请求消息如下: POST: http://[YourServer]/api/mgmnt/v2/INTEROP/cmAPI Body: API 描述文件,例如下面的Json文件Basic Authorization Username: 用户名 Basic Authorization Password: 密码 Content-Type Header: application/json ** 注意**:调用接口前,需要创建相应命名空间,本示例为INTEROP API 描述文件: { "swagger": "2.0", "info": { "description": "An API for coffee sales using InterSystems IRIS", "version": "1.0.0", "title": "Coffee Maker API", "license": { "name": "Apache 2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0.html" } }, "schemes": [ "https" ], "paths": { "/coffeemakers": { "post": { "description": "Returns all coffeemakers\n", "operationId": "QueryAll", "produces": [ "application/json" ], "parameters": [], "responses": { "200": { "description": "Success" }, "500": { "description": "Server error" } } } }, "/newcoffeemaker": { "post": { "description": "Add a new coffeemaker to the store. ID is autogenerated. Other info must be provided in the request body. Name and brand are required fields. Returns new coffeemaker\n", "operationId": "NewMaker", "produces": [ "application/json" ], "parameters": [ { "in": "body", "name": "body", "required": true, "schema": { "$ref": "#/definitions/CoffeeMaker" } } ], "responses": { "200": { "description": "Success" }, "400": { "description": "Invalid message body" }, "500": { "description": "Server error" } } } }, "/coffeemaker": { "post": { "description": "Retrieve existing coffeemaker given ID and data. Returns coffeemaker\n", "operationId": "QueryMaker", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "query", "description": "CoffeemakerID", "required": true, "type": "integer" }, { "name": "prod", "in": "query", "required": false, "type": "boolean" } ], "responses": { "200": { "description": "Success" }, "404": { "description": "Coffeemaker not found" }, "500": { "description": "Server error" } } }, "put": { "description": "Update existing coffeemaker given ID and data. Returns updated coffeemaker\n", "operationId": "EditMaker", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "query", "description": "CoffeemakerID", "required": true, "type": "integer" }, { "in": "body", "name": "body", "description": "coffeemaker info", "required": true, "schema": { "$ref": "#/definitions/CoffeeMaker" } }, { "name": "prod", "in": "query", "required": false, "type": "boolean" } ], "responses": { "200": { "description": "Success" }, "400": { "description": "Invalid message body" }, "404": { "description": "Coffeemaker not found" }, "500": { "description": "Server error" } } }, "delete": { "description": "Delete existing cofffeemaker given ID. Returns deleted coffeemaker\n", "operationId": "RemoveMaker", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "query", "description": "CoffeemakerID", "required": true, "type": "integer" }, { "name": "prod", "in": "query", "required": false, "type": "boolean" } ], "responses": { "200": { "description": "Success" }, "404": { "description": "Coffeemaker not found" } } } } }, "definitions": { "CoffeeMaker": { "type": "object", "properties": { "Name": { "type": "string" }, "Brand": { "type": "string" }, "Price": { "type": "number" }, "NumCups": { "type": "integer" }, "Color": { "type": "string" }, "Img": { "type": "string" } } } } } 返回消息: { "msg": "New application cmAPI created" }
文章
Michael Lei · 八月 31, 2022

修改IRIS For Health 网页图标

背景Background 大多数网站都有一个 "Fav.ico "文件,用于设置网页的图标。大多数用户有多个环境,开发、测试和生产环境。通常情况下,你很难一眼就看出你在哪个环境中。如果能直观地通过图标看到你所处的版本和环境,可以提供更好的用户体验。在这个例子中,所有的实例都被命名为 "ENSEMBLE"。注意,这是在2022.1上使用的IRIS FOR HEALTH。 默认图标是 IR 在这篇文章中,我们将把标识改为类似于以下的内容: 图标文件 图标文件安装在你的安装文件夹csp/broker/portal中 创建一个名为Archive的文件夹放在该文件夹中 复制并粘贴ISC_IRIS_icon.ico到这个文件夹,对旧图标进行备份 使用一个图标编辑器。我使用了在线创建和编辑ICO文件| RedKetchup,因为它很容易使用,并且有简单的文本选项。 将.ico文件复制到你的本地文件,并打开它(Icon-> Open) 5. 采取铅笔工具。清除任何旧的字母(提示:改变铅笔大小可以更容易操作)。 6. Click test. Set colour. Play around with the font. DON'T FORGET TO PRESS APPLY 7. 保存图标. 8. 在一个全新安装的文件夹(DRIVELETTER:\InterSystems\HealthConnect\CSP\broker)中替换图标 9. 重新加载管理门户。. 注意你可能需要在chrome/edge上做一个硬刷新页面(通过按shift同时点击重新加载按钮)。 请注意,上述步骤在升级时可能不会生效,保存任何使用的图标,以便你可以再次更换标识。
问题
Michael Lei · 四月 27, 2022

如何更改主键?

Hi, 请问如何更改表(有数据)上的主键?谢谢! 答: 如果数据已经存在,那么这是一项必须重视的任务,特别是如果存在继承或父/子关系,因为这将导致你的数据存储方案的改变。 最简单的方法是通过一个中间(临时)表来实现。 创建一个具有相同结构的新类,但有一个新的主键。使用SQL(不是合并命令)将数据从旧的类中移到它里面。删除旧类中的数据/索引,然后改变其中的主键。使用合并命令,将数据从新类移到旧类中。删除带有数据的新类。重建索引(如果有的话)。 几个有用的链接: MERGE 持久性对象和InterSystems IRIS SQL 持久性对象的介绍 如果仍然有问题,最好向WRC寻求帮助。 答: 如果数据已经存在,那么这是一项必须重视的任务,特别是如果存在继承或父/子关系,因为这将导致你的数据存储方案的改变。 最简单的方法是通过一个中间(临时)表来实现。 创建一个具有相同结构的新类,但有一个新的主键。使用SQL(不是合并命令)将数据从旧的类中移到它里面。删除旧类中的数据/索引,然后改变其中的主键。使用合并命令,将数据从新类移到旧类中。删除带有数据的新类。重建索引(如果有的话)。 几个有用的链接: MERGE
公告
Michael Lei · 十月 7, 2024

通过近似最近邻索引(已在向量搜索抢先体验计划中实现)加快向量搜索速度

我们最近在向量搜索抢险体验计划中提供了新版的 InterSystems IRIS,新版本采用了新的基于分层可导航小世界 (HNSW) 索引算法的近似最近邻索引。 这一新增功能可对大型向量数据集进行高效的近似最近邻搜索,从而显著提高查询性能和可扩缩性。 HNSW 算法旨在通过构建基于图形的结构来优化高维数据的向量搜索,从而更快地在大型向量集合中找到近似邻。 无论您使用的是推荐系统、自然语言处理,还是其他机器学习应用,HNSW 都能显著缩短搜索时间,同时允许您调整准确度水平,但准确度提高的代价是查询时间变慢。 HNSW 的主要优点包括: • 即使数据集规模不断扩大,也能加快搜索速度 • 减少内存占用,同时保持高准确度 • 与现有的 IRIS 向量搜索功能无缝集成 如何开始使用 最新版本现已通过向量搜索抢先体验计划提供。 要参与,请在此处注册,下载新版本并开始测试。 我们正在持续增强向量搜索的功能,因此您的反馈至关重要! 我们鼓励您探索性能改进方法,并与社区分享您的想法。 如果您在抢先体验阶段遇到任何问题或有任何反馈,请联系我。 祝您编码愉快!
文章
Hao Ma · 十月 28, 2024

配置Webgateway Conainter-补充

### 把CSP.conf保存在container之外 在创建webgateway的container时,可以使用`ISC_DATA_DIRECTORY=`参数, 选择把CSP文保存在主机而不仅仅是container内部。如下面的例子: 使用`volumnes`映射了主机的`./dur-wg-a`目录到container的`/dur`目录, 而command中的`ISC_DATA_DIRECTORY=/dur`会讲webgateway的配置文件, log文件等保存在主机。 ```yaml webgateway-apache: image: containers.intersystems.com/intersystems/webgateway-arm64:2024.1 container_name: wg-tls hostname: wg-tls ports: - "8080:80" - "4433:443" volumes: - ./webgateway/csp:/external - ./dur-wg-a:/dur environment: - TZ=CST-8 - ISC_CSP_CONF_FILE=/external/CSP-apache.conf - ISC_CSP_INI_FILE=/external/CSP-merge.ini - ISC_DATA_DIRECTORY=/dur ``` 需要注意的是,这种情况下, 当配置了`ISC_CSP_CONF_FILE`时,比如把定制的CSP.conf放在了`/dur/CSP.conf`, 实际上是创建了一个link到`/etc/apache2/mods-available`, 而最终会链接到`/etc/apache2/mods-enabled`. 真正工作的CSP.conf还是在`/etc/apache2/mods-enabled`. ### 在apache2加载网站 虽然绝大多数情况WebGateway Container只用于连接IRIS,但如果在测试或者演示环境中,希望在apache2中加入自己的网站或者网页, 可以简单的参考下面的说明。 在默认的`apache2.conf`里面默认的定义了3个directory, `, ,`,而在`sites-enabled`里面是这么配置的 ```zsh root@ac6fdedbac6b:/etc/apache2# cat sites-enabled/000-default.conf ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined root@ac6fdedbac6b:/etc/apache2# ``` 因为`000-default.conf`是默认生效的配置文件,因此把自动的网站放在/拷贝到`/var/www/html`目录是最简单的方案。 注意您的网站如果有js或者其他可执行的文件, 网站目录和文件的权限应该是755.
文章
Jeff Liu · 一月 8, 2021

ObjectScript类浏览器 - 以UML类图方式浏览ObjectScript类

你好! 本文简单介绍一款工具,帮您理解InterSystems产品(从IRIS到Caché、Ensemble以及HealthShare)中的类及其结构。 简言之,它将类或整个包可视化,显示类之间的关系,并向开发人员和团队领导提供各种信息,而无需到 Studio 中检查代码。 如果您正在学习InterSystems产品,经常查看项目,或只对InterSystems技术解决方案中的新内容感兴趣,欢迎阅读ObjectScript类浏览器概述! InterSystems 产品简介 IRIS(之前称为Caché) 是一个多模型DBMS。您可以使用SQL查询来访问它,也可以通过各种编程语言可用的接口与存储的对象和过程进行交互。但最多的还是使用DBMS原生内置语言--ObjectScript (COS) 开发应用程序。 Caché支持DBMS级别的类。有两种主要的类类型:Persistent(可以存储在数据库中)和 Registered(不存储在数据库中,扮演程序和处理程序的角色)。还有几种特殊的类类型:Serial(可集成到持久类中用于创建复杂数据类型(如:地址)的类),DataType(用于创建用户定义的数据类型)、Index、View 和 Stream。 进入类浏览器 Caché类浏览器是一个工具,它将Caché类的结构可视化为图表,显示类之间的依赖关系和所有相关信息,包括各种类元素的方法代码、查询、xData块、注释、文档和关键字。 功能 类浏览器使用扩展版UML类图进行可视化,因为Caché有一组很重要但不被标准UML支持的附加实体:查询、xData块、方法和属性的大量关键字(如System、ZenMethod、Hidden、ProcedureBlock等)、父子关系和一多关系、类类型等。 Caché 类浏览器(1.14.3版)允许您执行以下操作: 显示包、类图或整个包的层次结构; 编辑图表显示后的外观; 保存类图的当前图像; 保存一个图表的当前外观,并在将来恢复; 按图表或类树中显示的任何关键字搜索; 使用工具提示获得关于类、其属性、方法、参数、查询和xData块的完整信息; 查看方法、查询或xData块的代码; 启用或禁用任何图表元素的显示,包括图形图标。 为了更好理解下文内容,先看下类浏览器的如何对类进行可视化的。举个例子,让我们显示来自“samples”命名空间的“cinema”包: 详细信息和功能概述 左侧边栏包含一个包树。将鼠标指针放在包名称上,然后单击出现在其右侧的按钮以显示整个包。在包树中选择类,将其与其链接的类一起呈现。 类浏览器可以显示类之间的几种依赖关系类型: 1. 继承。以白色实心箭头显示,箭头指向继承的类; 2. 类之间的“关联”或关系。如果其中一个类的字段包含另一个类的类型,图表构建器将把它显示为关联关系; 3. 父子关系和一多关系:维护数据完整性的规则。 如果将鼠标指针指向该关系,则创建该关系的属性将高亮显示: 注意,类浏览器不会更深入,也不会为当前包之外的类绘制依赖关系。它将只显示当前包中的类,如果需要限制类浏览器查找类的深度,请使用“依赖级别”设置: 类本身显示为一个矩形,分为六个部分: 1. 类名:将鼠标指针指向类名,可以了解它是何时创建和修改的,查看注释以及所有分配给这个类的关键字。双击类头将打开其文档; 2. 类参数:所有带类型、关键字和注释的赋值参数。斜体的参数以及任何属性都有工具提示并且可以悬停; 3. 类属性与参数类似; 4. 方法:点击任何方法都可以查看其源代码。COS 语法将被高亮显示; 5. 查询:与方法类似--点击可以查看源代码; 6. xData块:主要包含XML数据的块。点击将显示块中格式化的源代码。 默认每个类都显示有许多图形图标。点击屏幕右上角的“帮助”按钮,了解每个图标的含义。如果您需要默认显示更严格或更包容的 UML 类图,以及任何类的任何部分,可以在设置部分禁用。 如果关系图太大,而且您也不太熟悉,可以使用快速图表搜索功能。包含您输入的关键字的任何部分的类将被高亮显示。要跳转到下一个匹配项,只需按 Enter 键或再次单击搜索按钮: 最后,在完成了图表编辑,去掉所有不必要关系,并将元素安放好,实现期望的外观之后,可以点击左下角的“下载”按钮来保存: 激活固定按钮 时,元素在当前类(或包)组的图表上的位置将被固定。例如,如果您选择A类和B类,然后用固定按钮保存视图,则再次选择A类和B类时将看到完全相同的视图,即使在重新启动浏览器或机器之后也不会变化。但是如果您只选择A类,布局将是默认的。 安装 要安装Caché类浏览器,只需将最新版本xml包导入到任何命名空间中。导入后就能看到名为hostname/ClassExplorer/(末尾的斜杠不能丢)的新web应用程序。 详细安装说明 1. 下载最新版Caché类浏览器压缩包; 2. 提取名为Cache/CacheClassExplorer-vX.X.X.xml的XML文件; 3. 使用以下方法之一将包导入任何命名空间: 1. 只需将XML文件拖到Studio上; 2. 使用系统管理门户:系统资源管理器 -> 类 -> 导入,并指定本地文件路径; 3. 使用terminal命令: do ##class(%Installer.Installer).InstallFromCommandLine(“Path/Installer.cls.xml”); 4. 读取导入日志--如果顺利安装,就可以通过 http://hostname/ClassExplorer/ 打开 web 应用程序。如果出了问题,请检查以下内容: 1. 是否有足够权限将类导入该命名空间; 2. web应用程序用户是否有足够权限访问不同的命名空间; 3. 如果出现错误404,只需检查是否在 URL 末尾添加了斜杠。 附加截图 [截图 1] DSVRDemo 包,鼠标指针悬停在一个类名上。 [截图 2] DataMining 包,在图表中搜索“TreeInput”关键字。 [截图 3] JavaDemo.JavaListSample 类中的方法代码视图。 [截图 4] 查看 ClassExplorer.Router 类中的 Xdata 块内容。 您可以尝试在标准SAMPLES命名空间中使用类浏览器:演示。这个项目的评测视频。 欢迎任何反馈、建议和意见--提交到这里或GitHub仓库。希望对您有用!
文章
姚 鑫 · 五月 23, 2021

第三章 发送HTTP请求

# 第三章 发送HTTP请求 # 发送HTTP请求 创建HTTP请求后,使用以下方法之一发送该请求: ### Delete() ```java method Delete(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP DELETE请求。 ### Get() ```java method Get(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP GET请求。此方法使Web服务器返回请求的页面。 ### Head() ```java method Head(location As %String, test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP Head请求。此方法使Web服务器仅返回响应头,而不返回正文。 ### Patch() ```java method Patch(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP修补程序请求。使用此方法可以对现有资源进行部分更改。 ### Post() ```java method Post(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP POST请求。使用此方法可将数据(如表单结果)发送到Web服务器,或上载文件。有关示例,请参阅“发送表单数据”。 ### Put() ```java method Put(location As %String = "", test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 发出HTTP PUT请求。使用此方法将数据上载到Web服务器。PUT请求并不常见。 ### Send() ```java method Send(type As %String, location As %String, test As %Integer = 0, reset As %Boolean = 1) as %Status ``` 将指定类型的HTTP请求发送到服务器。此方法通常由其他方法调用,但如果要使用不同的HTTP谓词,则提供此方法以供使用。此处`type`是指定HTTP谓词(如`“POST”`)的字符串。 在所有情况下: - 每个方法都返回一个状态,应该检查该状态。 - 如果该方法正确完成,则对此请求的响应将位于`HttpResponse`属性中。 - `Location`参数是要请求的URL,例如:`"/test.html"`。 - `Location`参数可以包含参数,假定这些参数已经URL转义,例如:`"/test.html?PARAM=%25VALUE"`将`PARAM`设置为等于`%VALUE`。 - 使用test参数检查正在发送的是您预期要发送的内容: - 如果test为1,则该方法不会连接到远程计算机,而是将其本应发送到Web服务器的内容输出到当前设备。 - 如果`test`为`2`,则在发出`HTTP`请求后将响应输出到当前设备。 - 在从服务器读取响应后,每个方法都会自动调用`Reset()`方法,除非`test=1`或`Reset=0`。 `Reset()`方法重置`%Net.HttpRequest`实例,以便它可以发出另一个请求。这比关闭此对象并创建新实例要快得多。这还会将`Location`标头的值移动到`Referer`标头。 ```java Set httprequest=##class(%Net.HttpRequest).%New() Set httprequest.Server="www.intersystems.com" Do httprequest.Get("/") ``` # 创建和发送多部分POST请求 要创建和发送多部分`POST`请求,请使用`%Net.MIMEPart`类,本书后面将详细讨论这些类。下面的示例发送包含两个部分的`POST`请求。第一部分包括文件二进制数据,第二部分包括文件名。 ```java ClassMethod CorrectWriteMIMEMessage3(header As %String) { // Create root MIMEPart Set RootMIMEPart=##class(%Net.MIMEPart).%New() //Create binary subpart and insert file data Set BinaryMIMEPart=##class(%Net.MIMEPart).%New() Set contentdisp="form-data; name="_$CHAR(34)_"file"_$CHAR(34)_"; filename=" _$CHAR(34)_"task4059.txt"_$CHAR(34) Do BinaryMIMEPart.SetHeader("Content-Disposition",contentdisp) Set stream=##class(%FileBinaryStream).%New() Set stream.Filename="/home/tabaiba/prueba.txt" Do stream.LinkToFile("/home/tabaiba/prueba.txt") Set BinaryMIMEPart.Body=stream Do BinaryMIMEPart.SetHeader("Content-Type","text/plain") // Create text subpart Set TextMIMEPart=##class(%Net.MIMEPart).%New() Set TextMIMEPart.Body=##class(%GlobalCharacterStream).%New() Do TextMIMEPart.Body.Write("/home/tabaiba/prueba.txt") // specify some headers Set TextMIMEPart.ContentType="text/plain" Set TextMIMEPart.ContentCharset="us-ascii" Do TextMIMEPart.SetHeader("Custom-header",header) // Insert both subparts into the root part Do RootMIMEPart.Parts.Insert(BinaryMIMEPart) // create MIME writer; write root MIME message Set writer=##class(%Net.MIMEWriter).%New() // Prepare outputting to the HttpRequestStream Set SentHttpRequest=##class(%Net.HttpRequest).%New() Set status=writer.OutputToStream(SentHttpRequest.EntityBody) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} // Now write down the content Set status=writer.WriteMIMEBody(RootMIMEPart) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} Set SentHttpRequest.Server="congrio" Set SentHttpRequest.Port = 8080 Set ContentType= "multipart/form-data; boundary="_RootMIMEPart.Boundary Set SentHttpRequest.ContentType=ContentType set url="alfresco/service/sample/upload.json?" _"alf_ticket=TICKET_caee62bf36f0ea5bd51194fce161f99092b75f62" set status=SentHttpRequest.Post(url,0) if $$$ISERR(status) {do $SYSTEM.Status.DisplayError(status) Quit} } ``` # 访问HTTP响应 发送`HTTP`请求后,请求的`HttpResponse`属性将更新。此属性是`%Net.HttpResponse`的实例。本节介绍如何使用`Response`对象。它包括以下主题: ## 访问响应的数据 HTTP响应的正文包含在响应的Data属性中。此属性包含流对象(特别是`%GlobalBinaryStream`)。要使用此流,请使用标准流方法:`Write()`、`WriteLine()`、`Read()`、`ReadLine()`、`Rewind()`、`MoveToEnd()`和`Clear()`。还可以使用流的`Size`属性。 请求的`ReadRawMode`属性控制如何读取响应正文。 - 默认情况下,此属性为False,并且InterSystems IRIS假定正文在响应的`HTTP`标头中指定的字符集内(并相应地转换该字符集)。 - 如果此属性为true,InterSystems IRIS将以原始模式读取正文(不执行字符集转换)。 还可以使用`OutputToDevice()`方法,该方法将完整响应写入当前设备。标头的顺序与Web服务器生成的顺序不同。 下面是一个简单的示例,在该示例中,我们将响应流复制到文件并保存: ```java /// w ##class(PHA.TEST.HTTP).Stream() ClassMethod Stream() { set request=##class(%Net.HttpRequest).%New() set request.Server="tools.ietf.org" set request.Https=1 set request.SSLConfiguration="yx" set status=request.Get("/html/rfc7158") if $$$ISERR(status) { do $system.OBJ.DisplayError() } else { set response=request.HttpResponse } Set file=##class(%FileCharacterStream).%New() set file.Filename="e:/temp/rfc7158.txt" set status=file.CopyFrom(response.Data) if $$$ISERR(status) { do $system.OBJ.DisplayError() } do file.%Close() q "" } ``` ## 按名称获取HTTP标头 `%Net.HttpResponse`类将其`HTTP`标头存储在InterSystems IRIS多维数组中。要访问标头,请使用以下方法: ### GetHeader() 返回给定头的值。 ### GetNextHeader() 返回给定标头之后的下一个标头的名称。 这些方法中的每一个都只有一个参数,即HTTP标头的名称字符串。 还可以使用`OutputHeaders()`方法,该方法将HTTP标头写入当前设备(尽管它们的生成顺序不同)。 ## 访问有关响应的其他信息 `%Net.HttpResponse` 类提供了存储HTTP响应其他特定部分的属性: - `StatusLine`存储HTTP状态行,这是响应的第一行。 - `StatusCode`存储HTTP状态码。 - `ReasonPhrase`存储与`StatusCode`对应的人类可读的原因。 - `ContentInfo`存储关于响应体的附加信息。 - `ContentType`存储了`Content-Type:`标头的值。 - `HttpVersion`表示发送响应的web服务器所支持的HTTP版本。
文章
姚 鑫 · 七月 7, 2021

第三十章 从类生成XML架构

# 第三十章 从类生成XML架构 本章介绍如何使用`%XML.Schema`从启用了XML的类生成XML架构。 # 概述 要生成为同一XML命名空间中的多个类定义类型的完整架构,请使用`%XML.Schema`构建架构,然后使用`%XML.Writer`为其生成输出。 # 从多个类构建架构 要构建XML架构,请执行以下操作: 1. 创建`%XML.Schema`实例。 2. 可以选择设置实例的属性: - 若要为任何其他未分配的类型指定命名空间,请指定`DefaultNamespace`属性。默认值为`NULL`。 - 默认情况下,类及其属性的类文档包含在模式的``元素中。 要禁用此功能,请将`IncludeDocumentation`属性指定为0。 注意:必须在调用`AddSchemaType()`方法之前设置这些属性。 3. 调用实例的`AddSchemaType()`方法。 ```java method AddSchemaType(class As %String, top As %String = "", format As %String, summary As %Boolean = 0, input As %Boolean = 0, refOnly As %Boolean = 0) as %Status ``` - class是支持xml的类的完整包名和类名。 - top 是可选的; 如果指定,它将覆盖该类的类型名。 - format指定此类型的格式。 它必须是`"literal"`(文字格式,默认),`"encoded"`(用于SOAP编码),`"encoded12"`(用于SOAP 1.2编码),或`"element"`。 值`“element”`与元素位于顶层的文字格式相同。 - summary,如果为true,将导致InterSystems IRIS启用xml的类的`XMLSUMMARY`参数。 如果指定了此参数,则模式将只包含该参数列出的属性。 - input,如果为true,将导致InterSystems IRIS获取输入模式,而不是输出模式。 在大多数情况下,输入模式和输出模式是相同的; 如果为类的属性指定`XMLIO`属性参数,则它们是不同的。 - refOnly如果为true,将导致InterSystems IRIS仅为引用的类型生成模式,而不是为给定的类和所有引用的类型生成模式。 这个方法返回一个应该被检查的状态。 4. 根据需要重复前面的步骤。 5. 如果要定义导入模式的位置,可以调用`DefineLocation()`方法。 ```java method DefineLocation(namespace As %String, location As %String) ``` namespace 是一个或多个引用类使用的名称空间,位置是对应模式(XSD文件)的URL或路径和文件名。 可以重复调用此方法来为多个导入的模式添加位置。 如果不使用这个方法,模式会包含一个``指令,但是不会给出模式的位置。 6. 要定义额外的``指令,可以调用`DefineExtraImports()`方法。 ```java method DefineExtraImports(namespace As %String, ByRef imports) ``` namespace是``指令应该添加到的命名空间,imports是一个多维数组,形式如下: Node| Value ---|--- `arrayname("namespace URI")` |字符串,给出此名称空间的模式(XSD文件)的位置。 # 为架构生成输出 按照上一节所述创建`%XML.Schema`的实例后,请执行以下操作以生成输出: 1. 调用实例的`GetSchema()`方法将架构作为文档对象模型(DOM)的节点返回。 此方法只有一个参数:模式的目标命名空间的URI。该方法返回`%XML.Node`的一个实例,该实例在“将XML文档表示为DOM”一章中介绍。 如果模式没有命名空间,请使用`“”`作为`GetSchema()`的参数。 2. 可以选择修改此DOM。 3. 要生成架构,请执行以下操作: a. 创建`%XML.Write`的实例,并可选择设置属性(如缩进)。 b. 可以选择调用编写器的`AddNamespace()`方法和其他方法,将名称空间声明添加到`` 元素。 因为架构可能引用简单的XSD类型,所以调用`AddSchemaNamespace()`来添加XML模式命名空间很有用。 c. 使用架构作为参数,调用编写器的`DocumentNode()`或`Tree()`方法。 # 示例 ## 简单的示例 第一个示例显示了基本步骤: ```java Set schemawriter=##class(%XML.Schema).%New() //添加类和包(例如) Set status=schemawriter.AddSchemaType("Facets.Test") //通过其URI(在本例中为NULL)检索架构 Set schema=schemawriter.GetSchema("") //create writer Set writer=##class(%XML.Writer).%New() Set writer.Indent=1 //use writer Do writer.DocumentNode(schema) ``` ## 更复杂的架构示例 ```java Class SchemaWriter.Person Extends (%Persistent, %XML.Adaptor) { Parameter NAMESPACE = "http://www.myapp.com"; Property Name As %Name; Property DOB As %Date(FORMAT = 5); Property PatientID as %String; Property HomeAddress as Address; Property OtherAddress as AddressOtherNS ; } ``` `Address`类定义在相同的XML名称空间(`“http://www.myapp.com”`)中,而`OtherAddress`类定义在不同的XML名称空间(`“http://www.other.com”`)中。 `Company`类也被定义在XML名称空间`“http://www.myapp.com”`中。 其定义如下: ```java Class SchemaWriter.Company Extends (%Persistent, %XML.Adaptor) { Parameter NAMESPACE = "http://www.myapp.com"; Property Name As %String; Property CompanyID As %String; Property HomeOffice As Address; } ``` 注意,不存在连接`Person`和`Company`类的属性关系。 要为命名空间`"http://www.myapp.com"`生成模式,我们可以使用以下方法: ```java ClassMethod Demo() { Set schema=##class(%XML.Schema).%New() Set schema.DefaultNamespace="http://www.myapp.com" Set status=schema.AddSchemaType("SchemaWriter.Person") Set status=schema.AddSchemaType("SchemaWriter.Company") Do schema.DefineLocation("http://www.other.com","c:/other-schema.xsd") Set schema=schema.GetSchema("http://www.myapp.com") //create writer Set writer=##class(%XML.Writer).%New() Set writer.Indent=1 Do writer.AddSchemaNamespace() Do writer.AddNamespace("http://www.myapp.com") Do writer.AddNamespace("http://www.other.com") Set status=writer.DocumentNode(schema) If $$$ISERR(status) {Do $system.OBJ.DisplayError() Quit } } ``` 输出如下: ```xml ``` 请注意以下几点: - 模式包括`Person`及其所有引用的类的类型,以及`Company`及其所有引用的类的类型。 - ``指令导入了`OtherAddress`类使用的命名空间; 因为我们使用了`DefineLocation()`,所以这个指令还指示了相应模式的位置。 - 因为我们在调用`DocumentNode()`之前使用了`AddSchemaNamespace()`和`AddNamespace()`,所以``元素包含了名称空间声明,它为这些名称空间定义了前缀。 - 如果我们没有使用`AddSchemaNamespace()`和`AddNamespace()`, ``将不会包含这些名称空间声明,模式将会如下所示: ```xml ... ```
文章
姚 鑫 · 七月 10, 2021

Caché XML

# Caché XML # [第一章 InterSystems XML工具简介☆☆☆☆](https://cn.community.intersystems.com/post/第一章-intersystems-xml工具简介) # [第二章 从对象写入XML输出☆☆☆☆☆](https://cn.community.intersystems.com/post/第二章-从对象写入xml输出) # [第三章 指定输出的字符集☆☆☆☆☆](https://cn.community.intersystems.com/post/第三章-指定输出的字符集) # [第四章 添加命名空间声明☆☆☆☆☆](https://cn.community.intersystems.com/post/第四章-添加命名空间声明) # [第五章 生成XML元素☆☆☆☆☆](https://cn.community.intersystems.com/post/第五章-生成xml元素) # [第六章 控制名称空间的使用☆☆☆☆☆](https://cn.community.intersystems.com/post/第六章-控制名称空间的使用) # [第七章 控制命名空间分配的外观☆☆☆☆☆](https://cn.community.intersystems.com/post/第七章-控制命名空间分配的外观) # [第八章 Other Options of the Writer☆☆☆☆☆](https://cn.community.intersystems.com/post/第八章-other-options-writer) # [第九章 将XML导入到对象中☆☆☆☆☆](https://cn.community.intersystems.com/post/第九章-将xml导入到对象中) # [第十章 XML元素和属性☆☆☆☆☆](https://cn.community.intersystems.com/post/第十章-xml元素和属性) # [第十一章 重新定义读取器处理相关对象的方式☆☆☆☆☆](https://cn.community.intersystems.com/post/第十一章-重新定义读取器处理相关对象的方式) # [第十二章 XML其他示例☆☆☆☆☆](https://cn.community.intersystems.com/post/第十二章-xml其他示例) # [第十三章 将XML文档表示为DOM☆☆☆☆☆](https://cn.community.intersystems.com/post/第十三章-将xml文档表示为dom) # [第十四章 XML获取当前节点信息☆☆☆☆☆](https://cn.community.intersystems.com/post/第十四章-xml获取当前节点信息) # [第十五章 XML检查属性☆☆☆☆☆](https://cn.community.intersystems.com/post/第十五章-xml检查属性) # [第十六章 创建或编辑DOM☆☆☆☆☆](https://cn.community.intersystems.com/post/第十六章-创建或编辑dom) # [第十七章 加密XML文档☆☆☆](https://cn.community.intersystems.com/post/第十七章-加密xml文档) # [第十八章 签署XML文档☆☆☆](https://cn.community.intersystems.com/post/第十八章-签署xml文档) # [第十九章 使用%XML.TextReader☆☆☆☆☆](https://cn.community.intersystems.com/post/第十九章-使用xmltextreader) # [第二十一章 使用%XML.TextReader 导航文档☆☆☆☆☆](https://cn.community.intersystems.com/post/第二十一章-使用xmltextreader-导航文档) # [第二十二章 计算XPath表达式☆☆☆☆☆](https://cn.community.intersystems.com/post/第二十二章-计算xpath表达式) # [第二十三章 执行XSLT转换☆☆☆](https://cn.community.intersystems.com/post/第二十三章-执行xslt转换) # [第二十四章 执行XSLT转换☆☆☆](https://cn.community.intersystems.com/post/第二十四章-执行xslt转换) # [第二十五章 添加和使用XSLT扩展函数☆☆☆](https://cn.community.intersystems.com/post/第二十五章-添加和使用xslt扩展函数) # [第二十六章 定制SAX解析器的使用方式☆☆☆☆](https://cn.community.intersystems.com/post/第二十六章-定制sax解析器的使用方式) # [第二十七章 定制SAX解析器的执行自定义实体解析☆☆☆☆](https://cn.community.intersystems.com/post/第二十七章-定制sax解析器的执行自定义实体解析) # [第二十八章 定制SAX解析器创建自定义内容处理程序☆☆☆☆](https://cn.community.intersystems.com/post/第二十八章-定制sax解析器创建自定义内容处理程序) # [第二十九章 从XML架构生成类☆☆☆☆](https://cn.community.intersystems.com/post/第二十九章-从xml架构生成类) # [第三十章 从类生成XML架构☆☆☆☆](https://cn.community.intersystems.com/post/第三十章-从类生成xml架构) # [第三十一章 检查命名空间和类☆☆☆☆](https://cn.community.intersystems.com/post/第三十一章-检查命名空间和类) # [第三十二章 XML基础知识概念☆☆☆☆☆](https://cn.community.intersystems.com/post/第三十二章-xml基础知识概念) # Caché XML 在CSDN 上 # [第一章 InterSystems XML工具简介☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117734468) # [第二章 从对象写入XML输出☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117765426) # [第三章 指定输出的字符集☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117804741) # [第四章 添加命名空间声明☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117837881) # [第五章 生成XML元素☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117867002) # [第六章 控制名称空间的使用☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117898116) # [第七章 控制命名空间分配的外观☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117928000) # [第八章 Other Options of the Writer☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117946239) # [第九章 将XML导入到对象中☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117980776) # [第十章 XML元素和属性☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118015143) # [第十一章 重新定义读取器处理相关对象的方式☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118046952) # [第十二章 XML其他示例☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118066297) # [第十三章 将XML文档表示为DOM☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118079066) # [第十四章 XML获取当前节点信息☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118099092) # [第十五章 XML检查属性☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118141298) # [第十六章 创建或编辑DOM☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118173945) # [第十七章 加密XML文档☆☆☆](https://yaoxin.blog.csdn.net/article/details/118205925) # [第十八章 签署XML文档☆☆☆](https://yaoxin.blog.csdn.net/article/details/118240046) # [第十九章 使用%XML.TextReader☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118265395) # [第二十章 使用%XML.TextReader 节点属性☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118291334) # [第二十一章 使用%XML.TextReader 导航文档☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118324134) # [第二十二章 计算XPath表达式☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118353276) # [第二十三章 执行XSLT转换☆☆☆](https://yaoxin.blog.csdn.net/article/details/118378341) # [第二十四章 执行XSLT转换☆☆☆](https://yaoxin.blog.csdn.net/article/details/118404243) # [第二十五章 添加和使用XSLT扩展函数☆☆☆](https://yaoxin.blog.csdn.net/article/details/118433664) # [第二十六章 定制SAX解析器的使用方式☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118456474) # [第二十七章 定制SAX解析器的执行自定义实体解析☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118478683) # [第二十八章 定制SAX解析器创建自定义内容处理程序☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118510180) # [第二十九章 从XML架构生成类☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118538567) # [第三十章 从类生成XML架构☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118565357) # [第三十一章 检查命名空间和类☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118594282) # [第三十二章 XML基础知识概念☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/118629407) # 预告 下一期系列将用一个月的时间连载,**《Caché File》**,**《Caché 关键字大全》**,敬请期待。 # 交流群 - QQ群号:410039091 - 笔者QQ:454115408 - 公众号:技术理科直男 - [intersys版主:姚鑫](https://cn.community.intersystems.com/user/236891/posts) ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9VqwzNP-1608850948003)(3E1D939266954ED48BDAEA9B8086B11E)\]](https://img-blog.csdnimg.cn/20201225070433434.png) # 大型免费课程,进群410039091获取课程目录 - 适合所有阶段程序员,总有一款你遗漏的知识点! ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210607145017460.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lhb3hpbjUyMTEyMw==,size_16,color_FFFFFF,t_70#pic_center)
文章
姚 鑫 · 三月 10, 2021

第七章 SQL表之间的关系

# 第七章 SQL表之间的关系 要在表之间强制执行引用完整性,可以定义外键。修改包含外键约束的表时,将检查外键约束。 # 定义外键 有几种方法可以在InterSystems SQL中定义外键: - 可以定义两个类之间的关系。定义关系会自动将外键约束投影到SQL。 - 可以在类定义中添加显式外键定义(对于关系未涵盖的情况)。 - 可以使用`CREATE TABLE`或`ALTER TABLE`命令添加外键。可以使用`ALTER TABLE`命令删除外键。 用作外键引用的`RowID`字段必须是公共的。引用隐藏的`RowID`?有关如何使用公用(或专用)`RowID`字段定义表的信息。 **一个表(类)的外键最大数目为400。** ## 外键引用完整性检查 外键约束可以指定更新或删除时的引用操作。 在`CREATE TABLE reference action`子句中描述了使用DDL定义这个引用操作。 在类定义引用的`OnDelete`和`OnUpdate`外键关键字中定义了一个持久化类来定义这个引用操作,该类投射到一个表。 在创建分片表时,这些引用操作必须设置为无操作。 默认情况下,InterSystemsIRIS®数据平台对`INSERT`,`UPDATE`和`DELETE`操作执行外键引用完整性检查。如果该操作将违反参照完整性,则不会执行;该操作将发出`SQLCODE -121,-122,-123或-124`错误。参照完整性检查失败会生成如下错误: ```java 错误#5540:SQLCODE:-124消息:表'HealthLanguage.FKey2'中至少存在1行,该行引用键NewIndex1-外键约束'NewForeignKey1'(字段'Pointer1')的NO ACTION引用操作失败[Execute + 5 ^ IRISSql16:USER] ``` 可以使用`$SYSTEM.SQL.SetFilerRefIntegrity()`方法在系统范围内禁止此检查。若要确定当前设置,请调用`$SYSTEM.SQL.CurrentSettings()`。 默认情况下,当删除带有外键的行时,InterSystems IRIS将在相应的被引用表的行上获取长期(直到事务结束)共享锁。这样可以防止在引用行上的`DELETE`事务完成之前对引用行进行更新或删除。这样可以防止删除引用行,然后回退删除引用行的情况。如果发生这种情况,外键将引用不存在的行。如果使用`NoCheck`定义外键,或者使用`%NOCHECK`或`%NOLOCK`指定引用行的`DELETE`,则不会获取此锁定。 使用持久性类定义定义表时,可以使用`NoCheck`关键字定义外键,以禁止将来对该外键进行检查。` CREATE TABLE`不提供此关键字选项。 可以使用`%NOCHECK`关键字选项禁止检查特定操作。 默认情况下,InterSystems IRIS还对以下操作执行外键引用完整性检查。如果指定的操作违反了引用完整性,则不执行该命令: - `ALTER TABLE DROP COLUMN`。 - `ALTER TABLE DROP CONSTRAINT`删除约束 问题`-317 SQLCODE`。 可以使用`SET`选项`COMPILEMODE=NOCHECK`来抑制外键完整性检查。 - 删除表。问题`-320 SQLCODE`。可以使用`SET`选项`COMPILEMODE = NOCHECK`来抑制外键插入检查。 - 触发器事件,包括事件之前。 例如,如果删除操作因违反外键引用完整性而不能执行,则不会执行`BEFORE DELETE`触发器。 在父/子关系中,没有定义子元素的顺序。 应用程序代码不能依赖于任何特定的顺序。 # 父表和子表 ## 定义父表和子表 在定义投射到表的持久类时,可以使用`relationship`属性指定两个表之间的父/子关系。 下面的例子定义了父表: ```java Class Sample.Invoice Extends %Persistent { Property Buyer As %String(MAXLEN=50) [Required]; Property InvoiceDate As %TimeStamp; Relationship Pchildren AS Sample.LineItem [ Cardinality = children, Inverse = Cparent ]; } ``` 下面的例子定义了一个子表: ```java Class Sample.LineItem Extends %Persistent { Property ProductSKU As %String; Property UnitPrice As %Numeric; Relationship Cparent AS Sample.Invoice [ Cardinality = parent, Inverse = Pchildren ]; } ``` 注意这两句话: - `Relationship Pchildren AS Sample.LineItem [ Cardinality = children, Inverse = Cparent ];` - `Relationship Cparent AS Sample.Invoice [ Cardinality = parent, Inverse = Pchildren ];` 在Management Portal SQL interface Catalog Details选项卡中,表信息提供了子表和/或父表的名称。 如果是子表,则提供对父表的引用,如:`parent->Sample.Invoice`。 子表本身可以是子表的父表。 (子表的子表被称为“孙”表。) 在本例中,表`Info`提供了父表和子表的名称。 ## 向父表和子表插入数据 在将相应的记录插入子表之前,必须将每个记录插入父表。 例如: ```java INSERT INTO Sample.Invoice (Buyer,InvoiceDate) VALUES ('yaoxin',CURRENT_TIMESTAMP) ``` ```java INSERT INTO Sample.LineItem (Cparent,ProductSKU,UnitPrice) VALUES (1,'45-A7',99.95) INSERT INTO Sample.LineItem (Cparent,ProductSKU,UnitPrice) VALUES (1,'22-A1',0.75) ``` ![image](/sites/default/files/inline/images/1_24.png) 尝试插入没有对应父记录ID的子记录时,会使用`%msg`子表`'Sample生成SQLCODE -104错误。 LineItem'`引用父表中不存在的行。 在子表上的插入操作期间,在父表的相应行上获得共享锁。 在插入子表行时,该行被锁定。 然后,锁被释放(直到事务结束时才被持有)。 这确保了在插入操作期间引用的父行不会被更改。 ## 标识父表和子表 在嵌入式SQL中,可以使用主机变量数组来标识父表和子表。 在子表中,主机变量数组的下标0被设置为父引用(`Cparent`),格式为parentref,下标1被设置为子记录ID,格式为`parentref|| childf`。 在父表中,没有定义下标0。 如下面的例子所示: ```java /// d ##class(PHA.TEST.SQL).FatherChildTable() ClassMethod FatherChildTable() { KILL tflds,SQLCODE,C1 &sql(DECLARE C1 CURSOR FOR SELECT *,%TABLENAME INTO :tflds(),:tname FROM Sample.Invoice) &sql(OPEN C1) IF SQLCODE