retrieve a record using Dynamics 365 Web API with empty alternate key - dynamics-crm

Problem
I'm trying to query records from Dynamics 365 using the Web API where a key attribute is null.
Approach
For testing purposes I created an entity with a string attribute, an integer attribute, and a decimal attribute. I then created an alternate key and put those three attributes in it, making this combination of attributes unique. I then created some records.
Querying the data using the Web API works as expected. I created a record with those values:
{
"my_string_key": "s1",
"my_integer_key": 1,
"my_decimal_key": 1.23
}
And query it like this:
/my_entities(my_string_key='s1',my_integer_key=1,my_decimal_key=1.23)
This returns the desired record.
However I can't get it to work when any of the key fields is empty, it always returns a 400 with message "Bad Request - Error in query syntax". Just for clarification: I purposely created records where one of the key attributes is empty, like this:
{
"my_integer_key": 1,
"my_decimal_key": 1.23
}
{
"my_string_key": "s1",
"my_decimal_key": 1.23
}
{
"my_string_key": "s1",
"my_integer_key": 1
}
Notice how each record is missing one of the key attributes, which effectively leaves it at null.
I tried using =null, =empty, ='', = and =Microsoft.OData.Core.ODataNullValue but nothing works. I tried to query them like this:
/my_entities(my_string_key=null,my_integer_key=1,my_decimal_key=1.23)
/my_entities(my_string_key='s1',my_integer_key=null,my_decimal_key=1.23)
/my_entities(my_string_key='s1',my_integer_key=1,my_decimal_key=null)
I also tried omitting the attribute with null in it, like this:
/my_entities(my_integer_key=1,my_decimal_key=1.23)
/my_entities(my_string_key='s1',my_decimal_key=1.23)
/my_entities(my_string_key='s1',my_integer_key=1)
None of this works. Can anyone provide a solution?
Final Words
I know that key attributes shouldn't be empty because that's not the point of key attributes. My scenario however requires to handle this specific case.
I also know that I could just use the $filter parameter, but I'd like a solution without having to resort to this "workaround". After all, it is a key and I'd like to treat it as one.

I think your efforts prove that key attributes cannot be empty. So, time for another approach.
Create a custom attribute and fill it with the combined values of the three key attributes. You can do this in a plugin registered in the pre operation stage of the Create and eventually Update messages of your entity.
Use the custom attribute as the key attribute.

Related

ServiceNow-How to get a record (INCIDENT/REQUEST/CHANGE)

Is there any common URL to navigate to serviceNow portal with number (INC/REQ/CHG)?
I have an common URL (INC/REQ/CHG) which can be navigated to ServiceNow portal by sys_id:
https://XXXXdev.service-now.com/nav_to.do?uri=task.do?sys_id=XXXXXXXXXXXXXXXXXXXXX
I have tried below URLs for incident but it is creating a new record
XXXXdev.service-now.com/nav_to.do?uri=incident.do?sysparm_order=INC0XXX
OR
XXXXdev.service-now.com/nav_to.do?uri=incident.do?number=INC00XXXX
No problem if there are different URLs for INC, REQ or CHG, I want a URL to see record by giving a number but not with sys_id.
From what you have described I believe you want:
https://[instance].service-now.com/incident.do?sysparm_query=number=INC1234567
https://[instance].service-now.com/sc_request.do?sysparm_query=number=REQ1234567
https://[instance].service-now.com/change_request.do?sysparm_query=number=CHG1234567
Or the catch all
https://[instance].service-now.com/task.do?sysparm_query=number=INC1234567
https://[instance].service-now.com/task.do?sysparm_query=number=REQ1234567
https://[instance].service-now.com/task.do?sysparm_query=number=CHG1234567
(see https://docs.servicenow.com/bundle/helsinki-servicenow-platform/page/use/navigation/concept/c_NavigatingByURL.html)
If you want to keep the outer frames of SN then use the nav_to.do?uri= version e.g.
https://[instance].service-now.com/nav_to.do?uri=sc_request.do?sysparm_query=number=REQ1234567
which is what #kirk has described.
You have a couple of options depending on what you're trying to do exactly.
Email
If you're trying to send this link in an email notification, you can use ${URI_REF} for the table that the notification is generated on.
This will automatically generate a link to the record.
You can also dot walk to another table, for example
Catalog Task up to the Requested Item ${request_item.URI_REF}
Current task up top the parent record ${parent.URI_REF}
Calculated
If you are looking to generate this based on some calculated method you can do this with the table name and the record number.
https://instance.service-now.com/nav_to.do?uri=/table_name.do?sysparm_que‌​ry=number=RECORD_NUMBER
For instance for a Change record with record number CHG0000123
https://instance.service-now.com/nav_to.do?uri=/change.do?sysparm_que‌​ry=number=CHG0000123
You may also reference a record by using a parent table, though this is more for an interesting note rather than a good practice. INC, REQ, and CHG all inherit from the Task table so you could do this.
https://instance.service-now.com/nav_to.do?uri=/task.do?sysparm_que‌​ry=number=CHG0000123
The drawback to using the parent table is that it won't have all fields and won't have the proper form layout. Mostly just an interesting exercise.
You may also leverage the text search and the system will pull up a record that matches the record number.
https://instance.service-now.com/nav_to.do?uri=/textsearch.do?sysparm_que‌​ry=number=CHG0000123
Note that this works out of the box and you could have configured search to not behave that way.
Business Rule
Another method inside of a Business Rule is to use the current.getLink() method. This will return a URL to the record. If you would like to add to a journal entry, you could use this
var currentLink = "[code]<a href='" + current.getLink() + "'>" + current.number + "</a>[/code]";
var journal = gs.getMessage("The new record is {0}", [currentLink]);
gr.work_notes = journalEntry;
Your initial URI will actually work with a NUMBER (like INC000001), assuming that number is actually the display field for the table (as it is by default):
https://XXXX.service-now.com/incident.do?sys_id=NUMBER
When you do a sys_id= lookup, we first lookup by the sys_id column. If it's not found there, we try a lookup on the display value (number), which will load the form exactly as you expect.
{yourinstance}.service-now.com/nav_to.do?uri=incident.do?sys_id={incidentNumber}
Replace incidentNumber with your incident number .

Mris rets does not allow search by ListingKey

I have a list of ListingKeys that are updated since 2015-01-01
Then Id like to fetch all the metadata and values based on that field (listingKey). I'm expecting to search by arrays of listingKeys.
So my DMQL2 query is
(Listingkey=10026515129,10026515170,10039422998,10039789519,10039789557,10039789596,10262631304,10383785355,10383787516,10389025847)
And the response from MRIS is
[PHRETS\Exceptions\RETSException]
'Listingkey' is not a valid search item for SearchType = 'Property' and Class = 'MRIS Residential'.
I'm surprised that 'Listingkey' is not searchable, its unlikely because its unique and a primary key, if we want to sync our database we could easily do this by ListingKey.
I'd suggest using www.retsmd.com to verify that the 2nd parameter in your Search request is a valid class name under the Property resource. Unless the server is misreporting something, I'd doubt that "MRIS Residential" is the value you want for the 2nd parameter.
If you could paste the Search line you're using completely, that would help. I regularly pull listings by primary key from that server so I know the software is capable of it.

GWT (smartgwt) grid sort selected records top

I have a grid where the user can select records via checkbox in front of every record. Now I have a requirement to sort the records based on their selection, so that all selected records should be placed top, followed by the not selected ones.
Is there any standard function to achieve this? As an alternative I thought of saving the selection state as an attribute on every record and sort based on the attribute.
The code for the column is:
gridRealmDt.setSelectionType(SelectionStyle.SIMPLE);
gridRealmDt.setSelectionAppearance(SelectionAppearance.CHECKBOX);
I try to describe the code I use as the affected code is deeply nested in our own framework classes.
gridRealmDt is a subclass of smartgwt ListGrid. In my Dialog a create an instance of the grid which creates an instance of a database bound datasource. When the dialog is loaded the records are fetched from the database and after that a registered an dataArrivedHandler where I select the records which match records from another table.
I tried to place the selection attribute in an extra field and use that for sortig before my other sort criteria, but this does not work. Here is the code for the field I am using.
ListGridField txtSelected = new ListGridField(SELECTED, "");
txtSelected.setHidden(true);
txtSelected.setSortByDisplayField(true);
txtSelected.setCanSortClientOnly(true);
When I do not set the canSortClientOnly property the order by is sent to my database resulting in an error, as the table does not contain that field, so I set the property. Now I get following error
Removing field from the sort Specifier array because it specifies canSort Client Only: true and all data is not yet client-side.
I also tried to use a sortNormilizer on the Name field which is my main sort criteria, but the normalizer is called before the selection value is set to the record.
record.setAttribute(CARealmDS.SELECTED,selected ? "a" : "b");
I also cannnot find a way to call the normalizer when selection changes.
Currently we are using Smart GWT Version 6.0p.
I don't think there is any standard function. Just use grid store update. Place checked items first.

CouchDB View with Multiple Parameters

I have a database that has an id column and a ts column. I need to be able to pass in the id and a start time and end time to retrieve all the values during the specified period. Can I do this with a view, or do I need the view to return all of the values that match the id? My concern is that I will be returning and parsing a lot more data than I really care about. Here is the format of my DB from my current view, which simply returns everything that matches the id...
{"id":"62db2aa3472dce80b1f2193fc21d52fd","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d52fd","_rev":"1-6aadd58f4f5dabacf6f4f638396246d0","id":"A-Meter-KW","ts":1437969600000,"tz":"New_York","val":"191kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d5100","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d5100","_rev":"1-71155153c0f03c49b02850bee5535e22","id":"A-Meter-KW","ts":1437968700000,"tz":"New_York","val":"190kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d45d7","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d45d7","_rev":"1-661511616958d45fdff3307600d2a9ed","id":"A-Meter-KW","ts":1437967800000,"tz":"New_York","val":"189kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d3c23","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d3c23","_rev":"1-4e97cfc6cb97ddc65f04efd9043b3abd","id":"A-Meter-KW","ts":1437966900000,"tz":"New_York","val":"188kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d2e35","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d2e35","_rev":"1-120298e95c9d2b4b9cdf438836b6c0c0","id":"A-Meter-KW","ts":1437966000000,"tz":"New_York","val":"187kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d22b0","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d22b0","_rev":"1-61e55d02bd8f0c601274b904f46c9f34","id":"A-Meter-KW","ts":1437965100000,"tz":"New_York","val":"186kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d1ce2","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d1ce2","_rev":"1-b4fe80563c70a40981e293af9c6a87b3","id":"A-Meter-KW","ts":1437964200000,"tz":"New_York","val":"185kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d1ccc","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d1ccc","_rev":"1-bdf1881c4270e68e7a7ed90a1d945228","id":"A-Meter-KW","ts":1437963300000,"tz":"New_York","val":"184kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d1303","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d1303","_rev":"1-404d5934fc882aa36e6d355d9a3485ae","id":"A-Meter-KW","ts":1437962400000,"tz":"New_York","val":"183kW"}},
{"id":"62db2aa3472dce80b1f2193fc21d0941","key":"A-Meter-KW","value":{"_id":"62db2aa3472dce80b1f2193fc21d0941","_rev":"1-64288d1c98e9b93aa6c546acb1e02078","id":"A-Meter-KW","ts":1437961500000,"tz":"New_York","val":"182kW"}}
...
... my current query is http://localhost:5984/hist/_design/hist/_view/byId?key=%22A-Meter-KW%22&descending=true. I'd like to passing a start and end time as well, something like http://localhost:5984/hist/_design/hist/_view/byId?key=%22A-Meter-KW%22&descending=true&start=1437963300000&end=1437966000000 but cannot figure out how to do this.
EDITED:
In order for Couch to match your query all the data (eg:A-Meter-KW and date) must be in the key, emitted by the view. So I think you might do something like:
emit([key,year,month,day],doc._id)
Then you can use the parameters startkey and endkey to filter the results properly.
Reference: http://guide.couchdb.org/draft/views.html#many
Side consideration: I would not use an "id" property inside my documents, because it could get easily confused with the "_id" (compulsory) one.

ServiceNow Encoded Query validation

I intend to let users specify encoded query in ServiceNow SOAP requests.
The problem is that if user specifies invalid query string (e.g. "?##" or "sometext"), ServiceNow do not return any exception, but every row or no rows at all.
Is there a way to check validity of encoded query via webservice?
Fandic,
If you know ahead of time which table the SOAP query will be running against (or can get that information from the user when they submit the query) you can set up your own web service exclusively for checking the validity of a query string.
GlideRecord has the "addedEncodedQuery" method for putting in encoded queries, and it has a getEncodedQuery for turning the current query into an encoded string. If you instantiate a GlideRecord object, and pass it an invalid query string like this:
var myGR = new GlideRecord('incident');
myGr.addEncodedQuery('invalid_field_foo=BAR');
You can then call getEncodedQuery out to see if it is valid:
var actual_query = myGR.getEncodedQuery(); //sys_idNotValidnull
You shouldn't do simple comparison between the input and the output, as the API doesn't guarantee that a valid query will be returned as the exact same string as entered. It's better to simply validate that the actual_query does not equal 'sys_idNotValidnull'.
I always recommend enabling the system property 'glide.invalid_query.returns_no_rows' to avoid this effect. The property does just what it says. I never understood why you'd ever want to return all rows for an invalid query. I've seen a number of cases where developers had a query defect and never knew it since rows were coming back.
You can use the below code so that query will return the result only when it correct.
gs.getSession().setStrictQuery(boolean);
This overrides the value of system property :
glide.invalid_query.returns_no_rows
Reference : https://docs.servicenow.com/bundle/istanbul-platform-administration/page/administer/reference-pages/reference/r_AvailableSystemProperties.html
Check the property value glide.invalid_query.returns_no_rows. If it's true, the invalid query returns no rows. If false (or not available) it is ignored.
This can be overridden with gs.getSession().setStrictQuery(boolean); on a script-by-script basis.

Resources