Hi.

I use the model class when I want to export some extra data (e.g properties from referenced objects) - model class attached is just a demo class to reproduce behaviour. I've also tried to export on origin class as you've suggested but the result is the same. If I open saved stream on server it looks as a valid PNG file. Maybe you should test with larger PNG file to reproduce the error, because it works also fine for me with smaller PNGs.

About IdKey index it is my habit to add the Unique parameter, although it is unique by it self :)...

I use a workaround in Load method which creates a valid Base64 string on output:

Set data=##class(User.Data).%OpenId(Ident)
Quit:data="" "null"

Set model=##class(User.Model).%New()
Set model.Ident=data.Ident

Do model.%JSONExportToString(.json)

Set jsonBase64={}.%FromJSON(json)
Do jsonBase64.%Set("PNG",data.PNG,"stream>base64")

Quit jsonBase64.%ToJSON()

I did also some logging on strings created with original Load method and workaround and it shows many differences... And I did it on IRIS server to ensure no extra encoding/decoding is done.

Viele Grüsse nach Wien.

Matjaž

Hi.

Tnx for reply. 

Classes:

Class User.API [ Abstract ]
{

ClassMethod Load(Ident As %String) As %String [ Language = objectscript ]
{
Set data=##class(User.Data).%OpenId(Ident)
Quit:data="" "null"

Set model=##class(User.Model).%New()
Set model.Ident=data.Ident
Do model.PNG.CopyFrom(data.PNG)

Do model.%JSONExportToString(.json)

Quit json
}

ClassMethod Save(Ident As %String, Data As %String) As %Status [ Language = objectscript ]
{
Set data=##class(User.Data).%OpenId(Ident)
If (data="")
{
Set data=##class(User.Data).%New()
Set data.Ident=Ident
}

Set model=##class(User.Model).%New()
Do model.%JSONImport(Data)

Do data.PNG.CopyFrom(model.PNG)

Quit data.%Save()
}

Class User.Model Extends (%RegisteredObject, %JSON.Adaptor)
{

Property Ident As %String;

Property PNG As %Stream.TmpBinary;

}

Class User.Data Extends %Persistent
{

Property Ident As %String;

Property PNG As %Stream.FileBinary;

Index Ident On Ident [ IdKey, Unique ];

Storage Default
{
<Data name="DataDefaultData">
<Value name="1">
<Value>%%CLASSNAME</Value>
</Value>
<Value name="2">
<Value>Ident</Value>
</Value>
<Value name="3">
<Value>PNG</Value>
</Value>
</Data>
<DataLocation>^User.DataD</DataLocation>
<DefaultData>DataDefaultData</DefaultData>
<IdLocation>^User.DataD</IdLocation>
<IndexLocation>^User.DataI</IndexLocation>
<StreamLocation>^User.DataS</StreamLocation>
<Type>%Storage.Persistent</Type>
}

}

ObjectScript class:

Class Packing.MasterData.Label Extends (%Persistent, %JSON.Adaptor) {

Property Department As %String;
Property Ident As %String;
Index LabelId On (Department, Ident) [ IdKey, Unique ];
Property Name As %String;
Index Name On Name;
Property Width As %Integer;
Property Height As %Integer;
Property DeclarationWidth As %Numeric;
Property DeclarationHeight As %Numeric;
Property ScriptTU As %Stream.FileBinary;
Property ScriptContainer As %Stream.FileBinary;
Property Status As %String(DISPLAYLIST = ",Aktivana,Neaktivna", VALUELIST = ",AC,NA") [ InitialExpression = "AC" ];
Property VarsXctsTU As array Of %String(MAXLEN = 500);
Property VarsXctsContainer As array Of %String(MAXLEN = 500);

Query List(Department As %String) As %SQLQuery(CONTAINID = 1) [ SqlProc ]
{
 SELECT Ident,Name FROM Label
 WHERE Department=:Department
 ORDER BY Name
}

}

C# class:

 private class SaveDataClass
        {
            public string Name {get; set;}
            public int Width { get; set; }
            public int Height { get; set; }
            public double DeclarationHeight { get; set; }
            public double DeclarationWidth { get; set; }
            public byte[] ScriptTU { get; set; }
            public byte[] ScriptContainer { get; set; }
            public Object VarsXctsTU { get; set; }
            public Object VarsXctsContainer { get; set; }
        }

C# deserialize code:

IRIS iris = IRIS.CreateIRIS(Program.Factory);
SaveDataClass aa=JsonSerializer.Deserialize<SaveDataClass>(iris.ClassMethodString("Packing.API.Administration", "LabelGetData", Program.Department, ddcLabelId.Text));
iris.Close();

LabelGetData method:

ClassMethod LabelGetData(Department As %String, Ident As %String) As %String [ Language = objectscript ]
{
Set label=##class(Packing.MasterData.Label).LabelIdOpen(Department, Ident)
Quit:label="" "" Do label.%JSONExportToString(.json) Quit json
}

JSON:

{"Ident":"CRO","Name":"HRVATSKI TEKST","VarsXctsTU":{"0":"..TechnicalProduct.Product.GTIN","1":"$Translate($ZDate(..UsefulBy,4,,2),\"/\",\".\")","2":"..Batch","3":"$FNUMBER(..CommercialWeight,\".\",3)","4":"..TechnicalProduct.Product.GTIN","5":"$TRANSLATE($JUSTIFY(..TechnicalProduct.Product.CUsInTU,2),\" \",0)","6":"$TRANSLATE($JUSTIFY($FNUMBER(..CommercialWeight*1000,,0),6),\" \",0)","7":"$EXTRACT($ZDate(..UsefulBy,8),3,*)","8":"..Batch","9":"$TRANSLATE($JUSTIFY(..%Id(),6),\" \",0)_$TRANSLATE($JUSTIFY(..TechnicalProduct.Ident,6),\" \",0)_$TRANSLATE($JUSTIFY(..TechnicalProduct.Product.CUsInTU,2),\" \",0)_$TRANSLATE($JUSTIFY($FNUMBER(..CommercialWeight*1000,,0),6),\" \",0)","10":"..TechnicalProduct.Ident","11":"\"001\"","12":"$SELECT(..TechnicalProduct.Product.Unit=\"KG\":$EXTRACT($TRANSLATE($JUSTIFY(..TechnicalProduct.EAN13TU,7),\" \",0),1,7)_$TRANSLATE($JUSTIFY($FNUMBER(..CommercialWeight*1000,,0),5),\" \",0),1:$EXTRACT($TRANSLATE($JUSTIFY(..TechnicalProduct.EAN13TU,12),\" \",0),1,12))","13":"$ZTime($ZTimeH($Piece(..CreatedAt,\" \",2),3),2)"}}

Properties for which I'm looking for solution are  VarsXctsTU and  VarsXctsContainer. Both are of type "array of %String". In C# class these properties are now declared as type Object, but they should be something like List<KeyValuePair<string,string>>, shouldn't they?

Hi.

It works although in the documentation stays:

method %SerializeObject(ByRef serial As %Binary, partial As %Integer = 0) as %Status [ Language = objectscript ]

This method retrieves all of the serial values for referenced objects and places them into the instance variables, Validates, Normalizes, and serializes the object (with a save of the persistent image if persistent).
This method is not meant to be called directly. It is called by %Save and by %GetSwizzleObject.

Tnx!

Regards,

Matjaž

Tnx for you answer, but I'm not sure I understand it. I don't have problem with index but with Open method:

        Set attributes=##class(Packing.Needs.Attributes).%New() //%SerializeObject
        Set attributes.Source="SYS"
        
        Set need=##class(Packing.Needs.State).StateIdOpen(json."Department",technicalProduct.%Id(),$ZDate(+$Horolog,3)_" 00:00:00",json."DeliveryBy",attributes,4) //attributes parameter should be in $List format