Question
Alexandr Ladoshkin · Apr 18, 2017

Get propertyy value in trigger

Hello,

I work with trigger and I need afeter update make INSERT into LogTable value of prorerty of saved class.  This is what i have in this monent.

S className = ..%ClassName(1)
S cls=##class(%Dictionary.CompiledClass).%OpenId(className)
F i = 1:1:cls.Properties.Count() {
    S prop = cls.Properties.GetAt(i)
    S propName = prop.Name
    S value={propName*N}
}

How Can I get value given "prop".

Thank you

0
0 506
Discussion (8)5
Log in or sign up to continue

Hi Alexandr,

If property is in the context of this class then you could try

set value=$property($THIS,propName)

If you make the code blocks outer method a generator, e.g. [ CodeMode = objectgenerator ]

then you can bake the property accessor into the underling INT code, e.g.

do %code.WriteLine(" set value=.."_propName)

this approach means you don't have to make any repetitive IO calls to dictionary at run time.

If you need an expanded example then I can bash something out.

Sean.

Dear Sean I would glad to get a code for update trigger that iterate on all updated properties of a derived class and writes log to a log table.

Here is an expanded example...
 

Method logProps(parent) As %String [ CodeMode = objectgenerator ]
{
  set x=%code
  for i=1:1:%compiledclass.Properties.Count() {
    #dim As %CompiledProperty
    set p=%compiledclass.Properties.GetAt(i)
    set name=p.Name
    if $extract(p.Name)'="%" do x.WriteLine(" do ..logProp("""_p.Name_""",.."_p.Name_")")
  }
}

Method logProp(propName, propValue)
{
  // call your macro logger here, or replace call to logProp with your macro above
}


Let's say you had a property...

  Property firstName As %String;


When you compile the class, your logProps method would look like this...

zlogProps(parent) public {
  do ..logProp("firstName",..firstName) }


There is an article on DC that explains method generators in more depth..

https://community.intersystems.com/post/exploring-code-generation-cach%C3%A9-method-generators

Are you using a trigger generator or writing your own code?  Can you send the whole trigger definition for review?

Trigger LogInsert [ Event = INSERT, Foreach = row/object, Time = AFTER ]
{
className = ..%ClassName(1)
cls=##class(%Dictionary.CompiledClass).%OpenId(className)
= 1:1:cls.Properties.Count() {

prop = cls.Properties.GetAt(i)
propName = prop.Name

prop.Name'["%" {
b
idRow = {Id}
"s value={"_propName_"}"
date=+$h,time=$p($h,",",2)
&sql(INSERT INTO LogClass (className, dateOfChange, fieldName, ip, newValue, oldValue, operation, timeOfChange, users)
            VALUES (:classname,:date,:propName, '192:168:1:1',:value,'','Insert',:time,'asfasf'))
}
}

You can combine triggers and method generators into trigger generators like this:

Class User.Class1 Extends %Persistent
{

Property prop1 As %String;

Property prop2 As %String;

Trigger NewTrigger [ CodeMode = objectgenerator, Event = INSERT, Time = AFTER ]
{
    #dim class As %Dictionary.CompiledClass = %compiledclass
    set proplist = ""
    for i=1:1:class.Properties.Count() {
        #dim prop As %Dictionary.CompiledProperty = class.Properties.GetAt(i)
        if prop.Internal || prop.Calculated || prop.ReadOnly || prop.Private || prop.Identity || prop.MultiDimensional continue
        set proplist = proplist _ $lb(prop.Name)
    }
    
    do %code.WriteLine($$$TAB _ "set ^dbg($i(^dbg)) = $lb({" _$lts(proplist, "},{") _ "})")
    quit $$$OK
}

/// do ##class(User.Class1).Test()
ClassMethod Test()
{
    do ..%KillExtent()
    kill ^dbg
    
    &sql(INSERT INTO Class1 (prop1, prop2) Values ('Alice', 1))
    &sql(INSERT INTO Class1 (prop1, prop2) Values ('Bob'  , 2))
    zw ^dbg
}

Test:

do ##class(User.Class1).Test()
^dbg=2
^dbg(1)=$lb("Alice",1)
^dbg(2)=$lb("Bob",2)

Here's whats going on during compilation.

  1. Build list of all relevant properties and write them into proplist variable. 
  2. Generate trigger code:  set ^dbg($i(^dbg)) = $lb({prop1}, {prop2})

And at runtime only set ^dbg gets hit

That said I'd have automatically generated some log class and called method log there, passing all properties.

Some docs:

Thank you all, dear friends for your help. You all really helped me.