Xrm.Tools.CRMWebAPI icon indicating copy to clipboard operation
Xrm.Tools.CRMWebAPI copied to clipboard

FetchXml query returns expando with invalid property names

Open BrettBailey opened this issue 6 years ago • 6 comments

If you build a fetch xml query with joins each entity is aliased eg

<link-entity name=""contact"" from=""contactid"" to=""cn_contactid"" link-type=""inner"" alias=""alias"">

this produces properties in the expando such as alias.fullname, alias.email1 etc which are not valid .net property names.

it should create an alias property which is also an expandoobject and add the properties to the alias collection.

This can be worked around by casting the expando to a dictionary but if you have to do that each time you may as well not bother making the expando in the first place.

image

BrettBailey avatar Dec 10 '18 16:12 BrettBailey

Agree this is painful the way OData works - similar occurs with Formatted values - Are you suggesting aliasfullname or adding an object alias with property of fullname. Either way we would have to process the object which is messy...Open for ideas here

davidyack avatar Dec 21 '18 17:12 davidyack

I think the best approach would be to create an object for the alias with properties for its fields such as firstname. This would produce a useable expando and protect from name clashes etc.

Alternatively, you could use a naming convention. for example instead of calling the property alias.fullname call it alias_fullname - that should be a simple text substitution and would result in a useable object but would clash with any existing alias_fullname fields.

Another approach would be to not convert the result to an expando at all - just return a dictionary.

BrettBailey avatar Jan 07 '19 12:01 BrettBailey

Hi Guys,

How was this resolved?

I have the following

var api = await GetAPI();

            CRMGetListOptions buOptions = new CRMGetListOptions()
            {
                FetchXml = @"<fetch no-lock='true'><entity name='account'><attribute name='accountid'/><attribute name='name'/><attribute name='accountnumber'/><filter type='and'><condition attribute='accountnumber' operator='not-null'/></filter><link-entity name='contact' from='contactid' to='primarycontactid' link-type='inner' alias='contact'><attribute name='fullname'/></link-entity></entity></fetch>"
            };
            var accounts = await api.GetList("accounts", buOptions);
            foreach(dynamic account in accounts.List)
            {
                Console.WriteLine(account.accountid + " " +   account.name  + " " +  account.accountnumber);
                Console.WriteLine(account.contact.fullname);
            }

But getting the following

'System.Dynamic.ExpandoObject' does not contain a definition for 'contact'

simba22042 avatar Sep 16 '19 22:09 simba22042

That is not account.contact it's account["contact.fullname"] the property is the alias plus the field So you could do something like

    var myAccount = account as IDictionary<string, object>;
        
      Console.WriteLine(myAccount["contact.fullname"]);

davidyack avatar Sep 16 '19 23:09 davidyack

I was getting Cannot apply indexing with [] to an expression of type 'System.Dynamic.ExpandoObject' with Console.WriteLine(myAccount["contact.fullname"]); so had to cast the reference to the interface to access it:

Like ((IDictionary<String, Object>)account)["contact.fullname"];

simba22042 avatar Sep 17 '19 13:09 simba22042

Correct you can't do it on the expando directly that is why I had

var myAccount = account as IDictionary<string, object>;

Then you don't need to cast each line

davidyack avatar Sep 17 '19 15:09 davidyack