第十三章 Caché 定义和使用对象值属性

第十三章 Caché 定义和使用对象值属性

文中描述序列类和串行类是一种类。

定义和使用对象值属性

短语对象值属性通常指的是如下定义的属性:

Property PropName as Classname;

其中Classname是除集合或流之外的对象类的名称.(集合属性和流属性是前面几章中讨论的特殊情况。)通常,Classname是注册的对象类,持久性类或序列类(请参见下一节)。

要定义这样的属性,请定义该属性所引用的类,然后添加该属性。

变量:CLASSNAME参数

如果属性基于持久性类,则需要执行额外的步骤。在这种情况下,必须将该属性的CLASSNAME属性参数指定为1。此步骤影响Caché存储此属性的方式,并使Caché能够检索其指向的对象。

例如,假设MyApp.Payment指定了NoExtent,而MyApp.CreditCard是MyApp.Payment的子类。假设MyApp.CurrencyOrder包含MyApp.CreditCard类型的属性。该属性应将CLASSNAME指定为1:

Class MyApp.CurrencyOrder [ NoExtent ] 
{
Property Payment as MyApp.CreditCard (CLASSNAME=1);

//other class members
}

请注意,SQL箭头语法在这种情况下不起作用。 (可以改用合适的JOIN。)

重要说明:请勿为类型为序列化类的属性指定CLASSNAME = 1。不支持此用法。

简介序列化对象

序列化类扩展%SerialObject。这种类的目的是用作另一个对象类的属性。序列化对象中的值被序列化到父对象中。序列化对象也称为嵌入式(或可嵌入)对象。Caché处理序列化对象属性的方式与处理非串行对象属性的方式不同。

两者的区别如下:

  • 在将值分配给其中的属性之前,无需调用%New()创建序列化对象。
  • 如果序列化对象属性包含在持久性类中,则序列化对象的属性存储在持久性类的范围内。

要定义一个串行类,只需定义一个扩展%SerialObject的类,并根据需要添加属性和其他类成员。下面显示了一个示例:

Class Sample.Address Extends %SerialObject
{

/// The street address.
Property Street As %String(MAXLEN = 80);

/// The city name.
Property City As %String(MAXLEN = 80);

/// The 2-letter state abbreviation.
Property State As %String(MAXLEN = 2);

/// The 5-digit U.S. Zone Improvement Plan (ZIP) code.
Property Zip As %String(MAXLEN = 5);

}

可能的对象组合

下表显示了父类和该类中的对象值属性的可能组合:

/ 属性是注册的对象类 属性是持久类对象 属性是序列化类
父类是注册对象类 支持 支持但不常见 支持
父类是持久类 支持但不常见 支持 支持
父类是序列化类 不支持 不支持 支持

对象值属性的术语

在持久类中,有两个术语表示对象值属性:

  • 引用属性(基于其他持久对象的属性)
  • 嵌入式对象属性(基于序列化对象的属性)

指定对象属性的值

要设置对象值属性,请将该属性设置为等于适当类的实例的OREF。

请考虑以下情况:ClassA包含基于ClassB的属性PropB,其中ClassB是对象类:

Class MyApp.ClassA
{

Property PropB as MyApp.ClassB;

//additional class members
}

并且ClassB具有一个非串行类,它具有自己的一组属性Prop1,Prop2和Prop3。

假设MyClassAInstance是ClassA实例的OREF。若要为此实例设置PropB属性的值,请执行以下操作:

  1. 如果ClassB不是串行类,请首先:
  • 获取ClassB实例的OREF。
  • (可选)设置此实例的属性。可以稍后进行设置。
  • 将MyClassAInstance.PropB设置为等于该OREF。
  • 如果ClassB是串行类,则可以跳过此步骤。
  1. (可选)使用级联点语法设置属性的属性(即,设置MyClassAInstance.PropB的属性)。

例如:

 set myclassBInstance=##class(MyApp.ClassB).%New()
 set myClassBInstance.Prop1="abc"
 set myClassBInstance.Prop2="def"
 set myClassAInstance.PropB=myclassBInstance
 set myClassAInstance.PropB.Prop3="ghi"

请注意,此示例在创建实例后立即直接设置ClassB实例的属性,之后通过级联点语法更间接地设置。

以下步骤可以实现相同的目标:

 set myClassAInstance.PropB=##class(MyApp.ClassB).%New()
 set myClassAInstance.PropB.Prop1="abc"
 set myClassAInstance.PropB.Prop2="def"
 set myClassAInstance.PropB.Prop3="ghi"

相反,如果ClassB是串行类,则可以执行以下操作,而无需为ClassB调用%New():

 set myClassAInstance.PropB.Prop1="abc"
 set myClassAInstance.PropB.Prop2="def"
 set myClassAInstance.PropB.Prop3="ghi"

完整示例:

Class PHA.DEC.MOB.MyClassB Extends %SerialObject
{
    Property Street As %String(MAXLEN = 80);
    Property City As %String(MAXLEN = 80);
    Property State As %String(MAXLEN = 2);
    Property Zip As %String(MAXLEN = 5);
    }

Class PHA.OP.MOB.TestThree Extends %RegisteredObject
{
    Property age;
}
/// d ##class(PHA.OP.MOB.Test).TestSpecifyingValue()
ClassMethod TestSpecifyingValue()
{
	//序列类属性可以直接用点语法执行
	s mTwo=##class(PHA.OP.MOB.TestTwo).%New("1")
	s mTwo.mClassB.City="北京"
	s mTwo.mClassB.Street="长安街"
	//注册类必须先%New 赋值 才可以 否则报错<INVALID OREF>
	s mThree=##class(PHA.OP.MOB.TestThree).%New()
	s mTwo.address = mThree
	s mTwo.address.age = 20
	
	w mTwo.mClassB.City,!
	w mTwo.mClassB.Street,!
	w mTwo.address.age,!
}

保存更改

在使用持久类的情况下,保存包含的对象(即,包含object属性的实例)。无需直接保存对象属性,因为在保存包含对象时会自动保存该属性。

以下示例说明了这些原理。考虑以下持久性类:

Class MyApp.Customers Extends %Persistent
{

    Property Name As %String;
    
    Property HomeStreet As %String(MAXLEN = 80);

    Property HomeCity As MyApp.Cities;

}
Class MyApp.Cities Extends %Persistent
{

    Property City As %String(MAXLEN = 80);

    Property State As %String;

    Property ZIP As %String;

}

在这种情况下,我们可以创建MyApp.Customers的实例并按如下所示设置其属性:

/// d ##class(PHA.OP.MOB.Test).TestSaveChange()
ClassMethod TestSaveChange()
{
    set customer=##class(MyApp.Customers).%New()
    set customer.Name="O'Greavy,N."
    set customer.HomeStreet="1234 Main Street"
    set customer.HomeCity=##class(MyApp.Cities).%New()
    set customer.HomeCity.City="Overton"
    set customer.HomeCity.State="Any State"
    set customer.HomeCity.ZIP="啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊"
    set status=customer.%Save()
    if $$$ISERR(status) {
        d $system.Status.DisplayError(status)
    }
}
错误 #7201: 数据类型值'啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊'                                   的长度超过2允许的MAXLEN
  > 错误 #5802: 属性'MyApp.Cities:ZIP'上的数据类型验证失败,值等于"啊啊啊啊啊啊啊                        啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊"

这些步骤将一条新记录添加到MyApp.Customers,并将一条新记录添加到MyApp.Cities。

不用为MyApp.Cities调用%New(),我们可以打开一个现有记录:

/// d ##class(PHA.OP.MOB.Test).TestSaveOther()
ClassMethod TestSaveOther()
{
    set customer=##class(MyApp.Customers).%New()
    set customer.Name="Burton,J.K."
    set customer.HomeStreet="17 Milk Street"
    set customer.HomeCity=##class(MyApp.Cities).%OpenId(3)
    set status=customer.%Save()
    if $$$ISERR(status) {
        do $system.Status.DisplayError(status)
    }
}

在以下变体中,在添加新客户的过程中打开并修改了现有城市:

/// d ##class(PHA.OP.MOB.Test).TestSaveOtherModify()
ClassMethod TestSaveOtherModify()
{
    set customer=##class(MyApp.Customers).%New()
    set customer.Name="Emerson,S."
    set customer.HomeStreet="295 School Lane"
    set customer.HomeCity=##class(MyApp.Cities).%OpenId(2)
    set customer.HomeCity.ZIP="11111"
    set status=customer.%Save()
    if $$$ISERR(status) {
        do $system.Status.DisplayError(status)
    }
}


对象值属性的SQL映射

如前面所述,一个持久化类被映射为一个SQL表。本节介绍如何将此类的引用属性和嵌入式对象属性映射到SQL。

引用属性

引用属性被映射为包含引用对象的OID的ID部分的字段。例如,假设一个客户对象具有一个引用SalesRep对象的Rep属性。如果特定客户的销售代表的ID为12,则该客户的“代表”列中的条目也是12。由于此值与引用对象的ID列的特定行的值匹配,因此在执行任何联接或其他处理时可以使用此值。

请注意,在CachéSQL中,可以使用特殊的引用语法轻松地使用此类引用,以代替使用JOIN。例如:

SELECT Company->Name FROM Sample.Employee ORDER BY Company->Name

嵌入式对象属性

嵌入式对象属性被映射为父类表中的多列。映射中的一列包含序列化形式的整个对象(包括所有定界符和控制字符)。其余各列分别用于对象的一个属性。

对象属性的列名与对象属性本身的列名相同。对象的一种属性。其他列名称由对象属性的名称,下划线和嵌入对象内的属性组成。

例如,假设一个类具有一个Home属性,其中包含一个Address类型的嵌入式对象;房屋本身的属性包括Street 和 Country.。然后,嵌入式对象的映射包括名为“Home_Street”和“Home_Country”的列。

注意:(请注意,列名称是从属性Home而不是地址Address派生的。)

例如,示例类Sample.Person包含Home属性,该属性是Sample.Address类型的嵌入式对象。可以通过SQL使用Home的组件字段,如下所示:

SELECT Name, Home_City, Home_State FROM Sample.Person 
WHERE Home_City %STARTSWITH 'B'
ORDER BY Home_City

嵌入式对象还可以包括其他复杂的数据形式:

  • 引用属性的映射包括一个只读字段,该字段包含对象引用。
  • 数组的映射是作为表一部分的单个不可编辑的列。
  • 列表的映射作为列表字段作为其映射字段之一;
发布了13 篇原创文章 · 获赞 1 · 访问量 353

猜你喜欢

转载自blog.csdn.net/yaoxin521123/article/details/105087593
今日推荐