How to navigate to parent of Serial Object?
I have a serial object:
Class EmbedObj Extends %SerialObject
which is stored as a property of another object
Class ContainerObj Extends %Persistent
Property InnerObj As EmbedObj;
Property Foobar As %String;
Question:
From within the context of an instance of EmbedObj, how can I navigate to the containing instance of "ContainterObj" and find that value of its Foobar property?
Harder Question: Is there a way I can do this as part of SQLComputeCode? (my EmbedObj has a Calculated property which now needs to depend on the value of property Foobar of the containing object).
Thanks in advance for any help on how to walk this relationship via Object or SQL access.
For serial class, I'm afraid that's not possible because of its nature.
$this, $classname, etc. in the context of EmbedObj don't know anything about ContainerObj.
Use bidirectional Relationship.
And if so?
I have been trying this approach but I am hitting a wall. It appears that because I am inserting the value into the embedded object in the container, it is seeing this as an additional UPDATE and calling the TRIGGER again, resulting in a <FRAMESTACK>. Any ideas on how to prevent the <FRAMESTACK> error?
Here is my simplified code:
{
Try {
// get value of Foobar
NEW fb
SET fb= {Foobar}
// INSERT value into embedded Primary Environments
&sql(UPDATE ContainerObj (InnerObj_Foobar)
VALUES (:fb)
WHERE %ID=:{ID})
} Catch tError {
Do LOG^%ETN
Throw tError
}
}
Vitaliy,
Thank you very much for the working sample - I really appreciate it!! In the end I decided to go with the approach of just projecting the property from the container into the embedded obj because it ended up being better for my particular project. If I have to revisit this in the future because I need more than just that one property, I will definitely try out your example!
Thanks again,
Ben
Hi Ben,
from the hacker's toolbox:
{
Try {
// get value of Foobar
NEW fb
SET fb= {Foobar}
// just for debugging
wwrite "***",$STACK
&sql(UPDATE ContainerObj (InnerObj_Foobar)
VALUES (:fb)
WHERE %ID=:{ID})
Do LOG^%ETN
Throw tError
}
}
You have to find out by "hacking" a suitable value for MAXSTACK related to your application.
Inside the looping Trigger, there is no chance to identify the first run of the loop.
If you know a %variable (e.g. %BenMax) you may use it as well.
You only have to make sure it is initialized outside your trigger.
IF $i(%BenMax) > ..#MAXSTACK {
With SQL you can initial %BenMax by a static (independent of row) WHERE Condition
INSERT ..... WHERE my.BENMAX()=1 and ....
The ClassMethod BENMAX may look like this:
{ set %BenMax=$s(n:n,1:1) quit 1 }
Direct global update instead of SQL maybe?
Thank you all ... sometimes all it takes is a good night sleep :)
I figured out to avoid recursively updating the value via the trigger .... don't update it if I don't need to :)
Here is my code - it now works like a charm!
It's not the prettiest, but I think the simplest solution would be to avoid navigating to the parent object entirely: