前言
Caché 的一个关键特性是它结合了对象技术和 SQL。您可以为任何给定方案使用最方便的访问模式。
Caché 提供了有时称为对象数据库的东西:一个与面向对象编程语言相结合的数据库。因此,您可以编写灵活的代码来执行以下所有操作:
也就是说,您可以在任何给定时间选择适合您需求的访问模式。
在内部,所有访问都是通过直接全局访问完成的,您也可以在适当的时候以这种方式访问数据。(如果您有类定义,则不建议使用直接全局访问来更改数据)
Caché SQL
Caché提供了SQL的实现,称为Caché SQL。
Caché SQL 支持完整的入门级 SQL-92 标准,但有一些例外和几个特殊扩展。Caché SQL 还支持索引、触发器、BLOB 和存储过程(这些是典型的 RDBMS 功能,但不是 SQL-92 标准的一部分)。
您可以在Routines和方法中使用 Caché SQL。若要在这些上下文中使用 SQL,可以使用以下的两种方式:
&sql(SELECT COUNT(*) INTO :myvar FROM Sample.Person)
Write myvar
动态 SQL(%SQL.Statement 和%SQL.StatementResult 类),如下面的示例所示:
SET myquery = "SELECT TOP 5 Name,DOB FROM Sample.Person"
SET tStatement = ##class(%SQL.Statement).%New()
SET tStatus = tStatement.%Prepare(myquery)
SET rset = tStatement.%Execute()
//now use proprties of rset object
为了便于在对象应用程序中使用 SQL,Caché 在 SQL 中包含了许多对象扩展。
箭头运算符
这些扩展中最有趣的扩展之一是能够使用引用(“–>”)运算符跟踪对象引用。例如,假设您有一个供应商引用其他两个类的类:联系和地区.您可以使用引用运算符引用相关类的属性:
SELECT ID,Name,ContactInfo->Name
FROM Vendor
WHERE Vendor->Region->Name = 'Antarctica'
当然,也可以使用 SQL JOIN 语法表示相同的查询。引用运算符语法的优点是它简洁明了,一目了然地易于理解。
持久类的特殊选项
在 Caché 中,所有持久性类都扩展了 %Library.Persistent(也称为 %Persistent)。此类为Caché中的 object-SQL 对应关系提供了大部分框架。在持久性类中,您有如下选项:
延迟加载)。然后,您也可以使用该对象。例如: Set person=##class(Sample.Person).%OpenId(10)
Set person.Name="Andrew Park"
Set person.Address.City="Birmingham"
Do person.%Save()
同样,当您保存对象时,系统也会自动保存其所有对象值属性。这被称为深度保存。有一个选项可以改为执行浅保存。
持久类的 SQL 投影
对于任何持久性类,该类的每个实例都可用作表中的一行,您可以通过 SQL 对其进行查询和操作。
由于继承不是关系模型的一部分,因此类编译器将持久性类的“扁平化”表示形式投影为关系表。下表列出了如何将某些各种对象元素投影到 SQL:
| Object Concept | SQL Concept |
|---|---|
| Package | Schema |
| Class | Table |
| Data type property (数据类型属性) | Field |
| Embedded object | Set of fields |
| List property | List field |
| Array property | Child table |
| Stream property | BLOB |
| Index | Index |
| Class method marked as stored procedure | Stored procedure(存储过程) |
投影表包含该类的所有相应字段,包括继承的字段。
对象 IDs
每个对象在其所属的每个范围内都有一个唯一的 ID。在大多数情况下,您可以使用此 ID 来处理对象。此 ID 是 %Persistent 类的以下常用方法的参数:
Caché 会在您首次保存对象时分配ID值。任务是永久性的;您无法更改对象的 ID。删除或更改其他对象时,不会为对象分配新 ID。
任何 ID 在其范围内都是唯一的。
对象的 ID 按如下方式确定:
parentID||childID
其中 parentID是父对象的 ID,childID 是子对象在父子关系中未使用时将接收的 ID
SKU-447
此外,属性值不能更改。
CATEGORY12||SUBCATEGORYA
若要访问对象的 ID 值,请使用对象从 %Persistent 继承的 %Id() 实例方法。
在 SQL 中,对象的 ID 值可用作名为 %Id 的伪字段。
存储
每个持久性类定义都包含描述如何将类属性映射到实际存储它们的全局变量的信息。类编译器为类生成此信息,并在您修改和重新编译时对其进行更新。
查看此信息可能很有用,在极少数情况下,您可能希望更改某些详细信息(非常仔细)。对于持久性类,Studio 会在类定义中显示如下所示的内容:
<Storage name="Default">
<Data name="PersonDefaultData"><Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Name</Value>
</Value>
<Value name="3">
<Value>SSN</Value>
</Value>
<Value name="4">
<Value>DOB</Value>
</Value>
...
</Storage>
存储定义包括几个元素,这些元素指定存储数据的全局变量:
<DataLocation>^Sample.PersonD</DataLocation>
<IdLocation>^Sample.PersonD</IdLocation>
<IndexLocation>^Sample.PersonI</IndexLocation>
...
<StreamLocation>^Sample.PersonS</StreamLocation>
默认情况下,使用默认存储:
注意:
如果完整的类名很长,系统会自动使用类名的哈希形式。因此,当您查看存储定义时,有时可能会看到全局名称,例如 ^package1.pC347.VeryLongCla4F4AD。如果出于任何原因计划直接使用某个类的数据全局,请确保检查存储定义,以便知道全局变量的实际名称。
对于典型类,大多数数据都包含在数据全局中,其中包括如下节点:
| 节点 | 节点内容 |
|---|---|
| ^full_class_name(“id”) 其中 full_class_name 是包含包的完整类名,如有必要,将长度保持在 31 个字符以求散列。此外,id 是“对象 ID”中所述的对象 ID。 | $ListBuild返回的格式列表。在此列表中,存储的属性按存储定义中<值>元素的 name 属性给出的顺序列出。根据定义,不存储瞬态属性。流属性存储在类的流全局中 |
请注意以下几点:
元素使用非默认存储类。默认值为 %Library.CacheStorage;如果不使用此存储类,Caché 不会更新存储定义。另一个常用选项是 %Library.CacheSQLStorage,它主要用于支持在 Caché 提供类之前编写的应用程序。用于创建持久类和表的选项
若要创建持久性类及其相应的SQL表,可以执行以下任一操作:
Studio 定义基于 %Persistent 的类。编译类时,系统将创建表。%Persistent 的类,然后将记录加载到相应的 SQL 表中。%SQL.Util.Procedures 中的 CSVTOCLASS() 方法。访问数据
若要访问、修改和删除与持久性类关联的数据,您的代码可以执行以下任何或所有操作:
SQL。SQL(SQL 语句和结果集接口)。Caché SQL 适用于以下情况:
对象访问适用于以下情况:
查看存储的数据
本节演示,对于任何持久性对象,相同的值通过对象访问、SQL 访问和直接全局访问可见。
在工作室中,如果我们查看样本.人类,我们看到以下属性定义:
/// Person's name.
Property Name As %String(POPSPEC = "Name()") [ Required ];
...
/// Person's age.
/// This is a calculated field whose value is derived from DOB .
Property Age As %Integer [ details removed for this example ];
/// Person's Date of Birth.
Property DOB As %Date(POPSPEC = "Date()");
在终端中,我们可以打开一个存储对象并写入其属性值:
SAMPLES>set person=##class(Sample.Person).%OpenId(1)
SAMPLES>w person.Name
Newton,Dave R.
SAMPLES>w person.Age
14
SAMPLES>w person.DOB
58153
请注意,在这里我们看到DOB属性的文字存储值。我们可以调用一个方法来返回此属性的显示值:
SAMPLES>write person.DOBLogicalToDisplay(person.DOB)
03/20/2000
在管理门户中,我们可以浏览此类的存储数据,如下所示:

请注意,在本例中,我们将看到DOB属性的显示值。(在门户中,还有另一个用于执行查询的选项,使用该选项可以控制对结果是使用逻辑模式还是显示模式。
在门户中,我们还可以浏览包含此类数据的全局变量:

或者,在终端中,我们可以写入包含此实例的全局节点的值:
zw ^Sample.PersonD("1")
^Sample.PersonD(1)=$lb("","Newton,Dave R.","384-10-6538",58153,$lb("6977 First Street","Pueblo","AK",63163),
$lb("9984 Second Blvd","Washington","MN",42829),"",$lb("Red"))
存储 Caché SQL 的生成代码
对于 Caché SQL(用作嵌入式 SQL 时除外),系统会生成可重用的代码来访问数据。
首次执行 SQL 语句时,Caché 会优化查询并生成和存储检索数据的代码。它将代码与优化的查询文本一起存储在查询缓存中。请注意,此缓存是代码缓存,而不是数据缓存。
稍后,当您执行 SQL 语句时,Caché 会对其进行优化,然后将该查询的文本与查询缓存中的项进行比较。如果 Caché 找到与给定查询匹配的存储查询(除了空格等细微差异),它将使用为该查询存储的代码。
您可以查看查询缓存并删除其中的任何项目。