You can specify Logfile setting for logging and these settings for debug:

  • JavaDebug: Allow a Java debugger (such as Eclipse or JSwat) to attach. If True, enables Java debugging via TCP. The default is False.
  • JavaDebugPort: Specify the port on which to listen. The default is 8000.
  • JavaDebugSuspend: If Yes, suspend the JVM on start to wait for the debugger to attach. The default is No.

Documentation.

Here's an idea on how to do it without triggers altogether.

1. Set IsLeader property only in case member is a leader. So its 1 or NULL.

2. Add unique index on (Team, IsLeader). Unique index can have any number of NULL records.

3. If you try to add more than one leader, you'll get an error:

ERROR #5808: Key not unique: Utils.TeamMember:IsLeaderIndex:^Utils.TeamMemberI("IsLeaderIndex"," 1"," 1") [%SaveData+14^Utils.TeamMember.1:USER]

Sample code:

Class Utils.TeamMember Extends %Persistent
{

Property Team As %String;

Property Member As %String;

Property IsLeader(VALUELIST = ",1");

Index IsLeaderIndex On (Team, IsLeader) [ Unique ];

/// do ##class(Utils.TeamMember).Test()
ClassMethod Test(AddTwoLeaders = {$$$YES})
{
    do ..%KillExtent()
    write $System.Status.GetErrorText(..Add(1, "Alice"))
    write $System.Status.GetErrorText(..Add(1, "Bob"))
    write $System.Status.GetErrorText(..Add(1, "Clover"))
    write $System.Status.GetErrorText(..Add(1, "Dave", 1))
    if AddTwoLeaders {
        write $System.Status.GetErrorText(..Add(1, "Helen", 1))
    }
}

ClassMethod Add(Team, Member, IsLeader = "")
{
    set obj = ..%New()
    set obj.Team = Team
    set obj.Member = Member
    set obj.IsLeader = IsLeader
    quit obj.%Save()
}

}

is the import smart enough to figure out if a row already exists

As you can't specify an ID column during import, then no, SQL import wizard would only insert new rows.

is there some other utility that can check for keys first?

You can:

  • export/import underlying global(s)
  • use 3rd party SQL database explorers to generate UPDATE DDL statements from your data (DataGrip can do it for example), and then import this DDL into new namespace

1. Get list of all items in production (via Ens.Director:getProductionItems)

2. Iterate over items local array and for each item:

  • Get list of settings for an item (via Ens.Director:GetItemSettings)
  • Check if ReplyCodeActions is a setting for current item, if it is get it's value.
  • Write into any structure the pairs Item:ReplyCodeActionsValue

 

Structure can be anything you want:

  • Custom class
  • Dynamic object
  • %List
  • %ListOfDataTypes

That mainly depends on what do you want to do with this information later.

This line causes an error:

Write tMessage.Name,!

Your class does not have Name property, so it causes an error.

The following method works :

/// Do ##class(Testing.Messages.Session).test()
ClassMethod test()
{
    Set messagedata = "<?xml version=""1.0"" encoding=""UTF-8""?><session><sessionId>124364</sessionId><cabinet>demo</cabinet><eventType>IN</eventType><eventTime>20161006160154</eventTime><login>test</login><loginFirstName>test</loginFirstName><loginLastName>test</loginLastName></session>"
    Set reader = ##class(%XML.Reader).%New()
    Set status = reader.OpenString(messagedata)
    Do reader.Rewind()

    If $$$ISERR(status) {do $System.Status.DisplayError(status)}

    // Associate a class name with the XML element name
    Do reader.CorrelateRoot("Testing.Messages.Session")

    // Read objects from xml data
    While (reader.Next(.tMessage,.status)) {
        Do:$$$ISERR(status) $System.Status.DisplayError(status)
        Write tMessage.sessionId,!
    }
}

Terminal:

USER >do ##class(Testing.Messages.Session).test()
124364

Disclaimer. I am not familiar with EDI.

Some solutions would be:

  • Get official EDI 271 xsd schema files and import them into Caché
  • Alternatively you can read EDI 271 specification/check examples and write your own classes

Then you need a dtl to transform incoming message into your new classes. If there's a lot of them maybe it would be better to write one generic transformer or write a transformer generator based on class (which would generate transformation method based on class properties).

After that you  can transform your class object into json via several ways:

  • Old json via %ZEN.proxyObject/%ZEN.auxillary.jsonProvider
  • New json via dynamic objects

Yes. You can use cursors for that. In the following example rowlist contains list of affected ids. You can get it all at the end or get individual ids right before or after the update, or even decide on the update based on id/val values:

Class User.NewClass1 Extends %Persistent
{

Property val;

/// do ##class(User.NewClass1).Test()
ClassMethod Test()
{
   do ..%KillExtent()
   
   &sql(INSERT INTO NewClass1 SET val = 0)
   &sql(INSERT INTO NewClass1 SET val = 3)
   
   set rowlist = ""
   &sql(DECLARE NewClass1 CURSOR FOR
        SELECT %ID,val
        INTO :id, :val
        FROM NewClass1)
   
   &sql(OPEN NewClass1)
   for {
       &sql(FETCH NewClass1)
       quit:SQLCODE'=0
       set val2 = val*2
       write "Processing id: ", id,!
       set rowlist = rowlist _ $lb(id)
       &sql(UPDATE NewClass1 SET val = :val2 WHERE CURRENT OF NewClass1)
   }
   &sql(CLOSE NewClass1)
   
   zw rowlist
}
}

It would output in a terminal:

>do ##class(User.NewClass1).Test()
Processing id: 1
Processing id: 2
rowlist=$lb("1","2")

Documentation:

Here's an example:

Class User.NewClass1 Extends %Persistent
{

Property streams As list Of %Stream.GlobalCharacter;

ClassMethod Test()
{
    do ..%KillExtent()
    
    set obj = ..%New()
    set stream1 = ##class(%Stream.GlobalCharacter).%New()
    do stream1.WriteLine("Hi")
    set stream2 = ##class(%Stream.GlobalCharacter).%New()
    do stream2.WriteLine(123)
    
    do obj.streams.Insert(stream1)
    do obj.streams.Insert(stream2)
    write $System.Status.GetErrorText(obj.%Save())
    
    kill
    
    set obj = ..%OpenId(1)
    for i=1:1:obj.streams.Count() {
        write "Stream #", i, ": ", obj.streams.GetAt(i).Read($$$MaxCacheInt)
    }
}
}