Question
· 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

Discussion (8)1
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.

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

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: