Escrito por

Software Engineer at Zarmik
Artigo Heloisa Paiva · 23 h atrás 5m read

Armazenando dados de classes e suas superclasses separadamente

Recentemente, uma pergunta na Comunidade foi feita por @Vermon Ferre sobre como armazenar dados de classes herdadas em globals diferentes. Então, decidi simular o seguinte comportamento: criei uma superclasse chamada Article.MainClass e duas subclasses, Article.Class1 e Article.Class2. Por padrão, quando cada classe estende %Persistent, o IRIS cria estruturas de armazenamento independentes para elas. Isso funcionará conforme o esperado se a primeira classe na lista de superclasses for %Persistent. Mas isso também significa que, se houver parâmetros na classe principal, eles serão perdidos, porque apenas os parâmetros da primeira classe da lista são herdados.


 
Class Article.MainClass Extends (%Persistent, %Populate) 
{ 

Storage Default 
{ 
<Data name="MainClassDefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
</Data> 
<DataLocation>^Article.MainClassD</DataLocation> 
<DefaultData>MainClassDefaultData</DefaultData> 
<IdLocation>^Article.MainClassD</IdLocation> 
<IndexLocation>^Article.MainClassI</IndexLocation> 
<StreamLocation>^Article.MainClassS</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
} 

Class Article.Class1 Extends (%Persistent, Article.MainClass, %Populate) 
{ 

Storage Default 
{ 
<Data name="Class1DefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
</Data> 
<DataLocation>^Article.Class1D</DataLocation> 
<DefaultData>Class1DefaultData</DefaultData> 
<IdLocation>^Article.Class1D</IdLocation> 
<IndexLocation>^Article.Class1I</IndexLocation> 
<StreamLocation>^Article.Class1S</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
} 

Class Article.Class2 Extends (%Persistent, Article.MainClass, %Populate) 
{ 

Storage Default 
{ 
<Data name="Class2DefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
</Data> 
<DataLocation>^Article.Class2D</DataLocation> 
<DefaultData>Class2DefaultData</DefaultData> 
<IdLocation>^Article.Class2D</IdLocation> 
<IndexLocation>^Article.Class2I</IndexLocation> 
<StreamLocation>^Article.Class2S</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
}

Por preguiça, incluí %Populate na lista de herança. O motivo pelo qual os dados permanecem separados, embora Class1 e Class2 herdem de MainClass, deve-se à Definição de Armazenamento (Storage Definition) gerada pelo compilador. Se você olhar a tag DataLocation no bloco de armazenamento XML, verá que cada classe aponta para sua própria global exclusiva:

Article.MainClass uses ^Article.MainClassD
Article.Class1 uses ^Article.Class1D
Article.Class2 uses ^Article.Class2D

Como esses "Data Locations" são exclusivos, uma instância de Class1 nunca é gravada fisicamente na mesma global que uma instância independente de MainClass.

Podemos ver que funciona como deveria nas globals após chamar Populate() para todas as classes.


Para ver como os dados reais são organizados, adicionei propriedades à hierarquia: MainProp na superclasse, e Class1Prop e Class2Prop nas respectivas subclasses. 

Class Article.MainClass Extends (%Persistent, %Populate) 
{ 

Property MainProp As %Integer; 

Storage Default 
{ 
<Data name="MainClassDefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
<Value name="2"> 
<Value>MainProp</Value> 
</Value> 
</Data> 
<DataLocation>^Article.MainClassD</DataLocation> 
<DefaultData>MainClassDefaultData</DefaultData> 
<IdLocation>^Article.MainClassD</IdLocation> 
<IndexLocation>^Article.MainClassI</IndexLocation> 
<StreamLocation>^Article.MainClassS</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
} 

Class Article.Class1 Extends (%Persistent, Article.MainClass, %Populate) 
{ 

Property Class1Prop As %Date; 

Storage Default 
{ 
<Data name="Class1DefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
<Value name="2"> 
<Value>Class1Prop</Value> 
</Value> 
<Value name="3"> 
<Value>MainProp</Value> 
</Value> 
</Data> 
<DataLocation>^Article.Class1D</DataLocation> 
<DefaultData>Class1DefaultData</DefaultData> 
<IdLocation>^Article.Class1D</IdLocation> 
<IndexLocation>^Article.Class1I</IndexLocation> 
<StreamLocation>^Article.Class1S</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
} 

Class Article.Class2 Extends (%Persistent, Article.MainClass, %Populate) 
{ 

Property Class2Prop; 

Storage Default 
{ 
<Data name="Class2DefaultData"> 
<Value name="1"> 
<Value>%%CLASSNAME</Value> 
</Value> 
<Value name="2"> 
<Value>Class2Prop</Value> 
</Value> 
<Value name="3"> 
<Value>MainProp</Value> 
</Value> 
</Data> 
<DataLocation>^Article.Class2D</DataLocation> 
<DefaultData>Class2DefaultData</DefaultData> 
<IdLocation>^Article.Class2D</IdLocation> 
<IndexLocation>^Article.Class2I</IndexLocation> 
<StreamLocation>^Article.Class2S</StreamLocation> 
<Type>%Storage.Persistent</Type> 
} 
} 

Quando recompilei e populei os dados, a separação ficou ainda mais clara através do bloco <Storage> na definição da classe.

A seção <Data name="...DefaultData"> é essencialmente um mapa que diz ao IRIS exatamente qual dado vai para qual nó da global. Em Article.Class1, o XML de armazenamento se parece com isso:

<Data name="Class1DefaultData">
<Value name="1"><Value>%%CLASSNAME</Value></Value>
<Value name="2"><Value>Class1Prop</Value></Value>
<Value name="3"><Value>MainProp</Value></Value>
</Data>

Este XML nos diz que quando um objeto da Class1 é salvo em ^Article.Class1D, a primeira parte da string da global é o nome da classe, a segunda é a propriedade da subclasse (Class1Prop) e a terceira é a propriedade herdada (MainProp).

Agora, ao chamar Populate() para todas as classes, confirmei que ^Article.MainClassD contém apenas instâncias criadas especificamente como objetos MainClass, mantendo apenas o valor de MainProp. Enquanto isso, as globals das subclasses contêm suas propriedades específicas junto com as herdadas. 

Esta arquitetura permite consultar uma subclasse específica com alto desempenho, pois o banco de dados não precisa filtrar uma tabela compartilhada massiva para encontrar os registros.