<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1779808403156438496</id><updated>2012-02-16T13:08:37.236Z</updated><category term='.NET enum'/><category term='Dynamics AX performance'/><category term='CLR in Dynamics AX'/><title type='text'>AX Developer tips</title><subtitle type='html'>This blog provides some developer tips and HOWTOs for Dynamics AX developers.
I hope you'll enjoy reading it.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1779808403156438496.post-3593891219788537655</id><published>2009-03-07T22:59:00.005Z</published><updated>2009-03-08T00:49:41.640Z</updated><title type='text'>LINQ in X++</title><content type='html'>LINQ (Language INtegrated Query) was introduced in C# 3.0 and was created for unified SQL-like inquiry interface to any data source: database, XML files, or object collections.&lt;br /&gt;&lt;br /&gt;In C# it can be performed in SQL-like format or through extention methods:&lt;br /&gt;collection.Where(....), collection.Select(....)&lt;br /&gt;&lt;br /&gt;In X++ SQL for DB access is already implemented, but sometimes developers need to fetch objects from collections (Lists, Maps, Sets...) by some specific criteria. This is usualy performed iterating objects and comparing their properties to specific value.&lt;br /&gt;&lt;br /&gt;To simplify this approach I wrote small framework which allows to select objects from collections (List in my case) using predecative conditions.&lt;br /&gt;&lt;br /&gt;Lets imageine we have simple class &lt;strong&gt;QueryListTEST&lt;/strong&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;class QueryListTEST&lt;br /&gt;{&lt;br /&gt;boolean flag;&lt;br /&gt;int value;&lt;br /&gt;str nam;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Boolean parmFlag(Boolean _flag = flag)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;flag = _flag;&lt;br /&gt;return flag;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Str parmName(Str _name = nam)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (!prmISDefault(_name))&lt;br /&gt;{&lt;br /&gt;nam = _name;&lt;br /&gt;}&lt;br /&gt;return nam;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Int parmValue(Int _value = value)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (!prmISDefault(_value))&lt;br /&gt;{&lt;br /&gt;value = _value;&lt;br /&gt;}&lt;br /&gt;return value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static QueryListTEST construct(str _name, boolean _flag, int _value)&lt;br /&gt;{&lt;br /&gt;QueryListTEST test = new QueryListTEST();&lt;br /&gt;;&lt;br /&gt;test.parmName(_name);&lt;br /&gt;test.parmFlag(_flag);&lt;br /&gt;test.parmValue(_value);&lt;br /&gt;return test;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;It contains 3 properties (parmMethods with 1 parameter with default value).&lt;br /&gt;Lets initialize list of objects of type &lt;strong&gt;QueryListTEST&lt;/strong&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;QueryList list = new QueryList();&lt;br /&gt;;&lt;br /&gt;list.addEnd(QueryListTEST::construct&lt;span style="color:#ff0000;"&gt;("",&lt;/span&gt; true, 0));&lt;br /&gt;list.addEnd(QueryListTEST::construct(&lt;span style="color:#ff0000;"&gt;"2"&lt;/span&gt;, false, -1));&lt;br /&gt;list.addEnd(QueryListTEST::construct(&lt;span style="color:#ff0000;"&gt;"3"&lt;/span&gt;, true, 2));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;QueryList&lt;/strong&gt; class is basically what I'm going to implement in this example. It extends &lt;strong&gt;List &lt;/strong&gt;but has one extra method &lt;strong&gt;select&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;found = list.select(new QueryListCondition_LessOrEq(&lt;span style="color:#ff0000;"&gt;'parmFlag'&lt;/span&gt;, false).and(new QueryListCondition_More(&lt;span style="color:#ff0000;"&gt;'parmName'&lt;/span&gt;, &lt;span style="color:#ff0000;"&gt;"&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;2&lt;/span&gt;&lt;span style="color:#ff0000;"&gt;"&lt;/span&gt;));&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;found&lt;/strong&gt; is also list of objects of the same type.&lt;/span&gt;&lt;br /&gt;As you can see, &lt;strong&gt;list &lt;/strong&gt;calls &lt;strong&gt;select &lt;/strong&gt;method, passing condition to it.&lt;br /&gt;Condition is represented by instance of class &lt;strong&gt;QueryListCondition. &lt;/strong&gt;&lt;br /&gt;It's an abstract class, which compares value of class instance property (first parameter in constructor) to some value (second parameter).&lt;br /&gt;Its child classes implement all possible comparison boolean operators:&lt;br /&gt;==, !=, &gt;, &gt;=, &lt;, &lt;= As you also can see, you can add several conditions, just calling methods of &lt;strong&gt;QueryListCondition.and(...) &lt;/strong&gt;or &lt;strong&gt;QueryListCondition.or(...)&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;What happens inside is &lt;strong&gt;QueryListCondition &lt;/strong&gt;adds condition, passed in methods &lt;strong&gt;and &lt;/strong&gt;and &lt;strong&gt;or &lt;/strong&gt;to its internal &lt;strong&gt;clhildConditon &lt;/strong&gt;list and returns itself after method call.&lt;br /&gt;&lt;br /&gt;Now let's see what happens inside &lt;strong&gt;QueryList.select&lt;/strong&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public QueryList select(QueryListCondition _condition , boolean _firstonly = false)&lt;br /&gt;{&lt;br /&gt;ListEnumerator elements = this.getEnumerator();&lt;br /&gt;QueryList foundList = new QueryList();&lt;br /&gt;Object current;&lt;br /&gt;;&lt;br /&gt;if (_condition)&lt;br /&gt;{&lt;br /&gt;while (elements.moveNext())&lt;br /&gt;{&lt;br /&gt;current = elements.current();&lt;br /&gt;if (_condition.result(current))&lt;br /&gt;{&lt;br /&gt;foundList.addEnd(current);&lt;br /&gt;if (_firstonly)&lt;br /&gt;{&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return foundList;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;QueryList &lt;/strong&gt;iterates through its elements and passes them to &lt;strong&gt;QueryListCondition &lt;/strong&gt;for check of &lt;strong&gt;result&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;QueryListCondition &lt;/strong&gt;itself checks its own result at first for particular object and results of all its inner conditions with regard to boolean operation &lt;strong&gt;and, or:&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public boolean result(Object _object = null)&lt;br /&gt;{&lt;br /&gt;boolean res;&lt;br /&gt;ListEnumerator conditionsEnumerator;&lt;br /&gt;ListEnumerator operations;&lt;br /&gt;QueryListCondition childCondition;&lt;br /&gt;boolean andOr;&lt;br /&gt;;&lt;br /&gt;if (_object)&lt;br /&gt;{&lt;br /&gt;this.parmObject(_object);&lt;br /&gt;}&lt;br /&gt;res = this.ownResult();&lt;br /&gt;if (childConditions)&lt;br /&gt;{&lt;br /&gt;conditionsEnumerator = childConditions.getEnumerator();&lt;br /&gt;operations = childConditionsOp.getEnumerator();&lt;br /&gt;while (conditionsEnumerator.moveNext() &amp;amp;&amp;amp; operations.moveNext())&lt;br /&gt;{&lt;br /&gt;childCondition = conditionsEnumerator.current();&lt;br /&gt;andOr = operations.current();&lt;br /&gt;res = andOr ? res &amp;amp;&amp;amp; childCondition.result(_object) : res childCondition.result(_object);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return res;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;br /&gt;In &lt;strong&gt;QueryListCondition.ownResult &lt;/strong&gt;condition fetches value from object property, validates it and returs proper result, according to condition type.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;QueryListObject &lt;/strong&gt;class represents object abstration for conditions. It takes Object as parameter in its construction and creates &lt;strong&gt;SysDictClass &lt;/strong&gt;object according to Object's class.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public Types parmPropertyType(str _parmMethodName)&lt;br /&gt;{&lt;br /&gt;SysDictMethod method = new SysDictMethod(UtilElementType::Class, thisClass.id(), _parmMethodName);&lt;br /&gt;;&lt;br /&gt;return method.returnType();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class QueryListObject&lt;br /&gt;{&lt;br /&gt;Object object;&lt;br /&gt;SysDictClass thisClass;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public ClassId classId()&lt;br /&gt;{&lt;br /&gt;return thisClass.id();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void new()&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Object parmObject(Object _object = object)&lt;br /&gt;{&lt;br /&gt;if (!object &amp;amp;&amp;amp; _object)&lt;br /&gt;{&lt;br /&gt;object = _object;&lt;br /&gt;thisClass = new SysDictClass(classIdGet(object));&lt;br /&gt;}&lt;br /&gt;return object;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public anytype parmValue(str _parmMethodName)&lt;br /&gt;{&lt;br /&gt;anyType value;&lt;br /&gt;;&lt;br /&gt;if (thisClass.hasObjectMethod(_parmMethodName))&lt;br /&gt;{&lt;br /&gt;new ExecutePermission().assert();&lt;br /&gt;//BP Deviation documented&lt;br /&gt;value = thisClass.callObject(_parmMethodName, object);&lt;br /&gt;}&lt;br /&gt;return value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public static QueryListObject newObject(object _object)&lt;br /&gt;{&lt;br /&gt;QueryListObject queryListObjet;&lt;br /&gt;;&lt;br /&gt;if (_object != null)&lt;br /&gt;{&lt;br /&gt;queryListObjet = new QueryListObject();&lt;br /&gt;queryListObjet.parmObject(_object);&lt;br /&gt;}&lt;br /&gt;return queryListObjet;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Then when &lt;strong&gt;QueryListCondition &lt;/strong&gt;fetches value from object using property name, it refers to &lt;strong&gt;QueryListObject &lt;/strong&gt;to invoke property method:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public Anytype parmValue(str _propName = property)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;&lt;br /&gt;if (_propName &amp;amp;&amp;amp; queryListOBject)&lt;br /&gt;{&lt;br /&gt;value = queryListOBject.parmValue(_propName);&lt;br /&gt;}&lt;br /&gt;return value;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;It's also possible to pass another property value as value to compare:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;QueryListCondition prop2prop;&lt;br /&gt;;&lt;br /&gt;prop2prop = new QueryListCondition_Equal('parmName');&lt;br /&gt;prop2prop.parmProp2Compare('parmFlag');&lt;br /&gt;&lt;br /&gt;found = list.select(prop2prop);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;However I faced some X++ reflection problems in this framework. When either property or value to compare is null (0, '', dateNull, conNull), there is comparison problem (stack trace), since &lt;strong&gt;anytype &lt;/strong&gt;is used as return type in &lt;strong&gt;QueryListObject.value &lt;/strong&gt;and system doesn't know how to cast type.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;At first I relied on X++ reflection and wrote the next code:&lt;br /&gt;&lt;strong&gt;QueryListCondition.ownResult &lt;/strong&gt;looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean ownResult()&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;anyType val = this.parmValue();&lt;br /&gt;anyType val2Compare = this.parmValue2Compare();&lt;br /&gt;;&lt;br /&gt;if (typeOf(val) == typeOf(val2Compare) !val !val2Compare )&lt;br /&gt;{&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;ret = this.thisResult(val,val2Compare);&lt;br /&gt;}&lt;br /&gt;catch&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;Where method &lt;strong&gt;thisResult &lt;/strong&gt;is abstrat. Let's see its implementation for &gt;= condition:&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;QueryListCondition_MoreOrEq.thisResult:&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? !this.compareNumVal(_val2Compare) : false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = true;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val &gt;= _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;It checks, whether both of value and value to compare are set or not set. Depending on that it returns proper value. &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;It's easy to do with almost each type, but numeric types, such as &lt;strong&gt;Integer &lt;/strong&gt;or &lt;strong&gt;Real &lt;/strong&gt;because they can have negative values and that's why they not obviously compared to &lt;strong&gt;0&lt;/strong&gt;.&lt;/span&gt;&lt;br /&gt;To solve thi problem class &lt;strong&gt;QueryListObject &lt;/strong&gt;has method &lt;strong&gt;propertyType&lt;/strong&gt; which is supposed to return property type using &lt;strong&gt;SysDictMethod.returnType(...) &lt;/strong&gt;. Then, in &lt;strong&gt;QueryListCondition.thisResult &lt;/strong&gt;method next code isexecuted:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#006600;"&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : true;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#006600;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;QueryListCondition.compareNumVal &lt;/strong&gt;compares &lt;strong&gt;Real &lt;/strong&gt;value to &lt;strong&gt;0&lt;/strong&gt;. So it also applies for &lt;strong&gt;Integer &lt;/strong&gt;values.&lt;/span&gt;&lt;br /&gt;The problem in this case is that &lt;strong&gt;SysDictMEthod.returnType &lt;/strong&gt;always returns &lt;strong&gt;void.&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;But this can be solved by adding one extra parameter to &lt;strong&gt;QueryListCondition: propertyType&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;This small framework provides developers with simple access to objects in collections without serious performance degradation. Now you don't have to program collection objects itrerative comparison with several &lt;strong&gt;if else &lt;/strong&gt;statements and vast of status saving variables.&lt;br /&gt;&lt;br /&gt;Enjoy :)&lt;br /&gt;&lt;br /&gt;Be welcome to find code of &lt;strong&gt;QueryListCondition &lt;/strong&gt;and all it ancestors below&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;QueryListCondition&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean numericProperty()&lt;br /&gt;{&lt;br /&gt;return propertyType == Types::Integer propertyType == Types::Real;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected abstract boolean compareNumVal(real _numVal)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected abstract boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public final QueryListCondition and(QueryListCondition _condition)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (_condition)&lt;br /&gt;{&lt;br /&gt;childConditions.addEnd(_condition);&lt;br /&gt;childConditionsOp.addEnd(NoYes::Yes);&lt;br /&gt;}&lt;br /&gt;return this;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;abstract public class QueryListCondition&lt;br /&gt;{&lt;br /&gt;List childConditions;&lt;br /&gt;List childConditionsOp;&lt;br /&gt;anytype value;&lt;br /&gt;anytype value2Compare;&lt;br /&gt;str property, property2Compare;&lt;br /&gt;Object object;&lt;br /&gt;QueryListObject queryListObject;&lt;br /&gt;Types propertyType;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void new(str _property = '', anytype _value2Compare = null, Types _propertyType = Types::AnyType)&lt;br /&gt;{&lt;br /&gt;if (_property)&lt;br /&gt;{&lt;br /&gt;this.parmProperty(_property);&lt;br /&gt;}&lt;br /&gt;if (_value2Compare)&lt;br /&gt;{&lt;br /&gt;this.parmValue2Compare(_value2Compare);&lt;br /&gt;}&lt;br /&gt;if (_propertyType != Types::AnyType)&lt;br /&gt;{&lt;br /&gt;propertyType = _propertyType;&lt;br /&gt;}&lt;br /&gt;childConditions = new List(Types::Class);&lt;br /&gt;childConditionsOp = new List(Types::String);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public final QueryListCondition or(QueryListCondition _condition)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (_condition)&lt;br /&gt;{&lt;br /&gt;childConditions.addEnd(_condition);&lt;br /&gt;childConditionsOp.addEnd(NoYes::No);&lt;br /&gt;}&lt;br /&gt;return this;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected boolean ownResult()&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;anyType val = this.parmValue();&lt;br /&gt;anyType val2Compare = this.parmValue2Compare();&lt;br /&gt;;&lt;br /&gt;if (typeOf(val) == typeOf(val2Compare) !val !val2Compare )&lt;br /&gt;{&lt;br /&gt;try&lt;br /&gt;{&lt;br /&gt;ret = this.thisResult(val,val2Compare);&lt;br /&gt;}&lt;br /&gt;catch&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Object parmObject(Object _object = object)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (!prmIsDefault(_object))&lt;br /&gt;{&lt;br /&gt;object = _object;&lt;br /&gt;queryListObject = QueryListObject::newObject(object);&lt;br /&gt;propertyType = propertyType == Types::AnyType propertyType == Types::void&lt;br /&gt;? queryListObject.parmPropertyType(this.parmProperty())&lt;br /&gt;: propertyType;&lt;br /&gt;}&lt;br /&gt;return object;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public str parmProp2Compare(str _prop2Compare = property2Compare)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;property2Compare = _prop2Compare;&lt;br /&gt;return property2Compare;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public str parmProperty(str _property = property)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;property = _property;&lt;br /&gt;return property;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Anytype parmValue(str _propName = property)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;if (_propName &amp;amp;&amp;amp; queryListOBject)&lt;br /&gt;{&lt;br /&gt;value = queryListOBject.parmValue(_propName);&lt;br /&gt;}&lt;br /&gt;return value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public Anytype parmValue2Compare(Anytype _value2Compare = value2Compare)&lt;br /&gt;{&lt;br /&gt;;&lt;br /&gt;value2Compare = _value2Compare;&lt;br /&gt;if (property2Compare &amp;amp;&amp;amp; queryListOBject)&lt;br /&gt;{&lt;br /&gt;value2Compare = queryListOBject.parmValue(property2Compare);&lt;br /&gt;}&lt;br /&gt;return value2Compare;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public boolean result(Object _object = null)&lt;br /&gt;{&lt;br /&gt;boolean res;&lt;br /&gt;ListEnumerator conditionsEnumerator;&lt;br /&gt;ListEnumerator operations;&lt;br /&gt;QueryListCondition childCondition;&lt;br /&gt;boolean andOr;&lt;br /&gt;;&lt;br /&gt;if (_object)&lt;br /&gt;{&lt;br /&gt;this.parmObject(_object);&lt;br /&gt;}&lt;br /&gt;res = this.ownResult();&lt;br /&gt;if (childConditions)&lt;br /&gt;{&lt;br /&gt;conditionsEnumerator = childConditions.getEnumerator();&lt;br /&gt;operations = childConditionsOp.getEnumerator();&lt;br /&gt;while (conditionsEnumerator.moveNext() &amp;amp;&amp;amp; operations.moveNext())&lt;br /&gt;{&lt;br /&gt;childCondition = conditionsEnumerator.current();&lt;br /&gt;andOr = operations.current();&lt;br /&gt;res = andOr ? res &amp;amp;&amp;amp; childCondition.result(_object) : res childCondition.result(_object);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return res;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;QueryListCondition_Equal&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_Equal extends QueryListCondition&lt;br /&gt;{&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = true;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val == _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;br /&gt;{&lt;br /&gt;return _numVal == 0;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color:#000000;"&gt;QueryListCondition_NotEqual&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_NotEqual extends QueryListCondition&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret&lt;br /&gt;;&lt;br /&gt;if ((_val &amp;amp;&amp;amp; !_val2Compare) (!_val &amp;amp;&amp;amp; _val2Compare))&lt;br /&gt;{&lt;br /&gt;ret = true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val == _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{ &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;return _numVal != 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;QueryListCondition_More&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_More extends QueryListCondition&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? !this.compareNumVal(_val2Compare) : false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val &gt; _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;br /&gt;{&lt;br /&gt;return _numVal &gt; 0;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;QueryListCondition_MoreOrEq&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_MoreOrEq extends QueryListCondition&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? !this.compareNumVal(_val2Compare) : false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = true;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val &gt;= _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{ &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;return _numVal &gt;= 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;QueryListCondition_Less&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_Less extends QueryListCondition&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? !this.compareNumVal(_val2Compare) : true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = false;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val &lt;&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;br /&gt;{&lt;br /&gt;return _numVal &lt;&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;QueryListCondition_LessOrEq&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryListCondition_LessOrEq extends QueryListCondition&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean thisResult(anytype _val, anytype _val2Compare)&lt;br /&gt;{&lt;br /&gt;boolean ret;&lt;br /&gt;;&lt;br /&gt;if (_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? this.compareNumVal(_val) : false;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; _val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = this.numericProperty() ? !this.compareNumVal(_val2Compare) : true;&lt;br /&gt;}&lt;br /&gt;else if (!_val &amp;amp;&amp;amp; !_val2Compare)&lt;br /&gt;{&lt;br /&gt;ret = true;&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;ret = _val &gt; _val2Compare;&lt;br /&gt;}&lt;br /&gt;return ret;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;protected boolean compareNumVal(real _numVal)&lt;br /&gt;{&lt;br /&gt;return _numVal &lt;= 0; }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#000000;"&gt;&lt;strong&gt;QueryList&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public class QueryList extends List&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public void new(Types _type = Types::Class)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;{ &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;super(_type);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;public QueryList select(QueryListCondition _condition , boolean _firstonly = false)&lt;br /&gt;{&lt;br /&gt;ListEnumerator elements = this.getEnumerator();&lt;br /&gt;QueryList foundList = new QueryList();&lt;br /&gt;Object current;&lt;br /&gt;;&lt;br /&gt;if (_condition)&lt;br /&gt;{&lt;br /&gt;while (elements.moveNext())&lt;br /&gt;{&lt;br /&gt;current = elements.current();&lt;br /&gt;if (_condition.result(current))&lt;br /&gt;{&lt;br /&gt;foundList.addEnd(current);&lt;br /&gt;if (_firstonly)&lt;br /&gt;{&lt;br /&gt;break;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;return foundList;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#009900;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1779808403156438496-3593891219788537655?l=axdevposts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/3593891219788537655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1779808403156438496&amp;postID=3593891219788537655' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/3593891219788537655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/3593891219788537655'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/2009/03/linq-in-x.html' title='LINQ in X++'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1779808403156438496.post-7303588422464636678</id><published>2008-07-13T16:55:00.000Z</published><updated>2008-07-13T17:10:07.243Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dynamics AX performance'/><title type='text'>Dynamics AX Performance issue. Cross object references drawbacks.</title><content type='html'>Recently I'm working on framework for Dynamics AX 4.0. Project includes form tree control data viewing.&lt;br /&gt;&lt;br /&gt;Basically tree framework includes class representing the whole tree and each tree node.&lt;br /&gt;At first each tree node class instance (let's call it TreeItemClass) is associated with particular FormTreeItem storing reference to it (parmFormTreeItem()). Then reference to this instance is being stored in FormTreeItem.data() property.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_2guWxaVCP2k/SHo1exYSUZI/AAAAAAAAAl4/lX24fznDqCc/s1600-h/crossReference.jpg"&gt;&lt;img style="cursor: pointer; width: 382px; height: 109px;" src="http://2.bp.blogspot.com/_2guWxaVCP2k/SHo1exYSUZI/AAAAAAAAAl4/lX24fznDqCc/s320/crossReference.jpg" alt="" id="BLOGGER_PHOTO_ID_5222545520657060242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The issue appeared when tree was built and I was trying to expand it's node containing a lot of sub nodes. Each time I expanded a new node, expanding time increased.&lt;br /&gt;After throughly debugging I discovered that there were huge delays in object assignment.&lt;br /&gt;Probably the problem was in garbage collector, which tried to calculate references.&lt;br /&gt;&lt;br /&gt;Anyway, problem was solved by removing FormTreeItem reference from TreeItemClass and changing it to TreeItemIdx.&lt;br /&gt;&lt;br /&gt;So be careful with cross object refernces in your code and try to avoid it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1779808403156438496-7303588422464636678?l=axdevposts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/7303588422464636678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1779808403156438496&amp;postID=7303588422464636678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/7303588422464636678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/7303588422464636678'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/2008/07/dynamics-ax-performance-issue-cross.html' title='Dynamics AX Performance issue. Cross object references drawbacks.'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_2guWxaVCP2k/SHo1exYSUZI/AAAAAAAAAl4/lX24fznDqCc/s72-c/crossReference.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1779808403156438496.post-2511127537691031602</id><published>2008-07-02T09:48:00.000Z</published><updated>2008-07-02T09:55:25.847Z</updated><title type='text'>CLR Interoperbility. Problem with Assembly Versions</title><content type='html'>If you're using CLR interoperability to access external logic, you can perform construct objectes two possible ways:&lt;br /&gt;&lt;br /&gt;1. Add &lt;span style="font-weight: bold;"&gt;Reference &lt;/span&gt;and then construct needed object&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;Microsoft.Office.Interop.Outlook._Apllication appl = new Microsoft.Office.Interop.Outlook.ApllicationClass();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;2. Also you can use&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;CLRObject appl = new CLRObject("Microsoft.Office.Interop.Outlook.ApllicationClass") ;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Using th first approach you're strictly tied to certain version of assembly. So, for instance, if user doesn't have Office 2007, assembly reference in DAX 4.0 will not be compiled, since certain 12th version is specified on it. So to be sure user will not receive this problem it's preferable to use second approach. How ever then you don't have an option to use .NET intelisence.&lt;br /&gt;&lt;br /&gt;I'm looking forward fixing this issue in DAX 2009&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1779808403156438496-2511127537691031602?l=axdevposts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/2511127537691031602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1779808403156438496&amp;postID=2511127537691031602' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/2511127537691031602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/2511127537691031602'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/2008/07/clr-interoperbility-problem-with.html' title='CLR Interoperbility. Problem with Assembly Versions'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1779808403156438496.post-1779829825566267486</id><published>2008-06-02T15:35:00.001Z</published><updated>2008-06-02T15:42:50.125Z</updated><title type='text'>Updating records without FORUDATE statement</title><content type='html'>I had an experience on previous project when I couldn't have inserted record in database because it was selected from another scope on server with &lt;span style="font-family: courier new;"&gt;forupdate &lt;/span&gt;parameter and then passed to another class to either insert or update it. Such kind of transfer was made due to abstraction of record initializer and to have the only place where record is written to DB.&lt;br /&gt;&lt;br /&gt;The error saying that record was not selected for update was thrown.&lt;br /&gt;&lt;br /&gt;But solution can be found in "Inside Dynamics AX" book.&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: courier new;" class="docEmphasis"&gt;skipTTSCheck &lt;/span&gt;method can be called with parameter &lt;span style="font-family: courier new;"&gt;true &lt;/span&gt;on record in place where the record is written.&lt;br /&gt;So by forcing skip of TTS check even record which was not selected for upadate can be written.&lt;br /&gt;&lt;br /&gt;Though "last writer" rule applies here...&lt;br /&gt;Anyway this record processing was expected to take place only from single machine at one concrete moment of time using batch processing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1779808403156438496-1779829825566267486?l=axdevposts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/1779829825566267486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1779808403156438496&amp;postID=1779829825566267486' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/1779829825566267486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/1779829825566267486'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/2008/06/updating-records-without-forudate.html' title='Updating records without FORUDATE statement'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1779808403156438496.post-3442225220754861758</id><published>2008-06-02T15:22:00.000Z</published><updated>2008-06-02T15:35:00.638Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='CLR in Dynamics AX'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET enum'/><title type='text'>.NET enumerations in Dynamics AX</title><content type='html'>As you know starting from DAX 4.0 .NET interoperability was introduced.&lt;br /&gt;You can easily instantiate .NET classes either likewise COM or by directly calling constructor method:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 153, 0);"&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Microsoft.Office.Interop.Outlook._Application outlookApplication = &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;    new Microsoft.Office.Interop.Outlook.ApplicationClass();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;it is the same with&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-family:courier new;"&gt;Microsoft.Office.Interop.Outlook._Application outlookApplication =&lt;br /&gt;   new     CLRObject(&lt;span style="color: rgb(255, 0, 0);"&gt;"Microsoft.Office.Interop.Outlook.ApplicationClass"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;Although usage of .NET objects is quiet common to COM, you cannot pass enum parameter to .NET object as &lt;span style="font-family:courier new;"&gt;int &lt;/span&gt;or &lt;span style="font-family:courier new;"&gt;str&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Instead of doing it you have to initialize it this way:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Microsoft.Office.Interop.Outlook.OlItemType olAppointmentItem = CLRInterop::parseClrEnum(&lt;span style="color: rgb(255, 0, 0);"&gt;'Microsoft.Office.Interop.Outlook.OlItemType'&lt;/span&gt;,&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;br /&gt;                        'olAppointmentItem'&lt;/span&gt;);&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Here you're initializing type of new Outlook i&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;tem with type Appointment.&lt;br /&gt;&lt;br /&gt;This inconvenient trick should be held every time you want to initialize enum parameter. Anyway it is more convenient than defining macro values like is done for COM enumerations.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1779808403156438496-3442225220754861758?l=axdevposts.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://axdevposts.blogspot.com/feeds/3442225220754861758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1779808403156438496&amp;postID=3442225220754861758' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/3442225220754861758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1779808403156438496/posts/default/3442225220754861758'/><link rel='alternate' type='text/html' href='http://axdevposts.blogspot.com/2008/06/net-enumerations-in-dynamics-ax.html' title='.NET enumerations in Dynamics AX'/><author><name>Roman Ganopolskyi</name><uri>http://www.blogger.com/profile/09127162255171573446</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp1.blogger.com/_2guWxaVCP2k/SIX09i1I8tI/AAAAAAAAAmY/yrrq9STbOr8/S220/IMG_0517.JPG'/></author><thr:total>1</thr:total></entry></feed>
