How to convert persistent object to dynamic object
Hi devs!
Suppose I have an instance of a persistent class:
Set person = ##class(dc.Sample.Person).%OpenId(1)Class is an ancestor of %JSON.Adapter.
How can I convert it to dynamic object with the properties that person.%JSONExport() provides?
{"Name":"Elon Mask","Title":"Associate Accountant","Company":"InterSystems","Phone":"799-933-5569","DOB":"1926-12-11"}Couldn't find a right method.
set dynObj = ##class(%ZEN.Auxiliary.altJSONProvider).%ObjectToAET(person) works, but adds id and classname, which I don't want to be added:
zw dynObj
dynObj={"_class":"dc.Sample.Person","_id":1,"Name":"Elon Mask","Title":"Associate Accountant","Company":"InterSystems","Phone":"799-933-5569","DOB":31390} ;Thoughts?
Comments
set dynObj = {}.%FromJSON(Person.%ToJSON())Looks very promising, but doesn't work for me:
USER>set dynObj = {}.%FromJSON(person.%ToJSON())
SET dynObj = {}.%FromJSON(person.%ToJSON())
^
<METHOD DOES NOT EXIST> *%ToJSON,dc.Sample.Person
USER>
not just Sample.Person but also Sample.Address,
or whatever serial class you refer to require %JSON Adaptor.
then
set person=##class(Sample.Person).%OpenId(3)
>set sc=person.%JSONExportToString(.Jperson)
set zjson={}.%FromJSON(Jperson)
ZWRITE
Jperson="{"LIMIT":103,"Name":"O'Rielly,Xavier E.","SSN":"331-77-5308","DOB":"1957-05-26","Home":{"Street":"8757 Elm Place","City":"Miami","State":"FL","Zip":"92027"},"Office":{"Street":"413 First Drive","City":"Miami","State":"NH","Zip":"83830"},"Age":67,"RowVer":0}"
person=<OBJECT REFERENCE>[2@Sample.Person]
sc=1
zjson=<OBJECT REFERENCE>[13@%Library.DynamicObject]and there is your dynamic object
Wow, @Robert Cemper ! Thank you as usual!
But 3 lines. Could it be a one command by any chance? :)
I compete with the following:
/// Get JSON for a person with a given idClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Status
{
Set person = ##class(dc.Sample.Person).%OpenId(messageRequest.pathid)
set stream=##class(%Stream.TmpCharacter).%New()
d person.%JSONExportToStream(.stream)
return stream
}This works, but with an unnecessary "to stream, out of stream" exercise IMHO.
OK
To Stream needs 1 line 2 statements
ClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Stream.Object
{
set stream=##class(%Stream.TmpCharacter).%New(),sc=##class(dc.Sample.Person).%OpenId(messageRequest.pathid).%JSONExportToStream(.stream)
return stream
}To String is shorter (just 1 statement) as you don't need to initialize %String)
ClassMethod personsidGET(messageRequest As dc.Sample.v3rest.requests.personsidGET) As%Stringdo##class(dc.Sample.Person).%OpenId(messageRequest.pathid).%JSONExportToString(.string)
return string
{Yes. But you cannot return String in this method - either dynamic object, or Stream object.
BTW, I’d even expect this functionality over %JSON.Adapter, as there is an option to import (construct) persistent from dynamic in it:
Set person=##class(dc.Sample.Person).%New()
do person.%JSONImport(dynamicPerson)
But person.%JSONExport() does JSON string into device. Would be wonderful to have:
D person.%JSONExport(.dynobj)
That's a typical case,
where I write my personal ZZanyname function into %ZLANGF00.mac
to hide the details
According to the documentation, there is a parameter "pFormat" that has default value acelo, where:
- c - output the ObjectScript-specific "_class" and "_id" properties
So, if you just call the transform like this, it should work:
set dynObj = ##class(%ZEN.Auxiliary.altJSONProvider).%ObjectToAET(person, , , "aelo")
Thank you so much, @Laura Blázquez García ! This is a great catch!
This does the job! The only concern is that I'd love to see something like:
set dynObj=$System.JSON.Persistent2Dynamic(person)
Especially since VSCode highlights %Zen as a deprecated package. (Are there any plans? calling @Timothy Leavitt )
This question isn't really best for me, but I'd like to see something like what you suggested in https://github.com/intersystems/isc-json .
So the one-line non-deprecated way would be:
Set sc=person.%JSONExportToString(.json), dynObj = {}.%FromJSON(json)
// or if we have long objectsSet sc=person.%JSONExportToStream(.json), dynObj = {}.%FromJSON(json)
But I agree it would be nicer to have just one command!, like the one that @Laura Blázquez García pointed out.
I know this has already been answered several ways, but let's not overlook embedded SQL as an option.
&sql(select JSON_OBJECT('Name':Name,'Title':Title,'Company':Company,'Phone':Phone, 'DOB':DOB) INTO :person WHERE ID = 1)
set personobj = {}.%FromJSON(person)This can get a little unruly for tables with a lot of columns, but if you're wanting to pick out certain specific columns or customize the JSON field names, this approach gives you that flexibility.
##class(%DynamicObject).%FromOref()
Is this what you were looking for?
which version ?
I tried and failed.
CLASS DOES NOT EXIST>%FromOref+8^%Library.DynamicObject.1 *%Library.EntityProjectionUtil
SAMPLES>w $zv
IRIS for Windows (x86-64) 2024.3 (Build 217U) Thu Nov 14 2024 17:59:58 EST
IRIS 2025.1.CE: the error is the same.
Why the %Library.EntityProjectionUtil class is missing in the system is a good question for developers.
Yes! That'd be ideal!
💡 This question is considered a Key Question. More details here.