When querying Dynamics 365 via the Web API there are several operators to choose from to filter the queried data. One of those operators is contains which actually appears twice.
One is the OData contains function (you'll find it under the heading 'Standard query functions'):
https://msdn.microsoft.com/en-us/library/gg334767.aspx#Filter%20results
Example:
$filter=contains(name,'(sample)')
The other one is an implementation of the Dynamics 365 Web API itself:
https://msdn.microsoft.com/en-us/library/mt608053.aspx
I tried with this one, but only got a Generic SQL error:
$filter=Microsoft.Dynamics.CRM.Contains(PropertyName='name',PropertyValue='(sample)')
What's the difference? And maybe someone can even tell me how to call the Web API version of contains correctly?
Latest documentation confirms $filter=contains(name,'(sample)') is the only working syntax with web api. As Jatin says, OData filter is converted into Query Expression behind the scenes, some articles (this & this) conveys possible solution is using Like operator directly in C# Query Expression.
We don't have Like operator equivalent functions in web api.
My attempts & observations:
Microsoft.Dynamics.CRM.Contains - Generic SQL error.
$filter=like(name,'%test%') - An unknown function with name 'like' was found. This may also be a function import or a key lookup on a navigation property, which is not allowed.
$filter=contains(name, 'test') - working
I think both methods are equivalent. The Web API filter function is added to support a standard OData filter function. The Contains function is a result of exposing all condition operators supported within CRM as OData functions. Please search ConditionOperator enumerations in D365 documentation for information about the Contains operator. It mentions the reason behind SQL error. Copying the same below:
You must use the Contains operator for only those attributes that are enabled for full-text indexing. Otherwise, you will receive a generic SQL error message while retrieving data. In a Microsoft Dynamics 365 default installation, only the attributes of the KBArticle (article) entity are enabled for full-text indexing.
It is preferable to use Web API filter function since it's more idiomatic. What error do you encounter using it? I suppose the root cause for both might be same since the OData filter query gets converted to D365 query expression in the back end and contains filter should be getting translated to the Contains condition operators.
Related
I'm trying to create a small app that displays some simple visualizations from data indexed on Elasticsearch (on an AWS managed Elasticsearch service).
Since, to the best of my knowledge, the degree of access control that AWS offers over its ES service is based on allowing specific HTTP verbs (GET, POST, etc), to simplify my life and the ES admin's, I'm granting this app "read only" permissions, so only GET and HEAD.
However, I see that for its search API, ES exposes a GET endpoint that works with query string parameters, and a POST endpoint that works with a JSON based "Query DSL". This DSL seems to be the preferred method in all examples I have seen online and in the books.
Given the predominance of the Query DSL throughout the documentation, I was wondering:
Does the the Query DSL exposes functionality that standard query string parameters don't, or are they both functionally equivalent?
Does the POST search endpoint result in any data being actually POSTED, or is this only a workaround to allow to send JSON as a query that breaks a little bit with REST conventions?
As per the docs
You can use query parameters to define your search criteria directly in the request URI, rather than in the request body. Request URI searches do not support the full Elasticsearch Query DSL, but are handy for testing.
The GET behavior is slightly confusing but even Kibana sends a POST in the background when you perform a GET with a body. If you have to use GET, some query results might be unexpected. What's your exact use case? Which queries are we talking?
FYI more useful info is here and here.
I have an app written with reason-react using apollo-client. I have defined some fragments on the frontend to basically reuse some field definitions. I'm setting up automated tests for a components that uses fragments, but I keep getting this warning saying I need to use the IntrospectionFragmentMatcher.
'You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types. Apollo Client will not be able to accurately map fragments. To make this error go away, use the `IntrospectionFragmentMatcher` as described in the docs: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher'
I've tried setting up the fragment matcher according to the docs. The codegen result returns no types:
{
"__schema": {
"types": []
}
}
When I queried my server and looked at the manual method recommended by apollo-client, I noticed it would also return no types.
Another strange thing is that when I don't use the fragment matcher, I get the mocked response back but I just get the warnings from apollo. If I do use it then the mocked response doesn't return correctly.
Why would I query the graphql api for fragments defined in my frontend code? Why would I only received these errors when running the tests & using mock data, but not when running my actual application?
As the error states, the default fragment matcher does not work on intersection or union types. You will need to use Apollo's IntrospectionFragmentMatcher. It works by asking the server (introspecting) for information about your schema types, and then providing that information for reference to the cache so that it can match the fields accurately. It's not querying the server for information about the fragments you are defining on the front end, it's asking for data about the GraphQL schema that must be defined on your back end so that it can properly relate the two. There is an example in the documentation, also more information here.
As for why your server is not returning any types, that is a separate issue that would require more info to debug. If you're using Apollo Server, doublecheck your schema to make sure all the necessary types are defined properly and that you are passing them into the server when it's initialized.
In the LearnGraphQL.com sandbox if you click the < DOCS button in the upper right hand corner it reveals a "Documentation Explorer" which lists the following:
ROOT TYPES
-----------------------
query: BlogSchema
mutation: BlogMutations
What is the raw query that can be sent to a graphql server that will return this information?
Every GraphQL server, according to the spec, must support a set of queries for "introspection": http://graphql.org/docs/introspection/
This means you can use GraphQL queries to get information about that server's available types, fields, queries, mutations, directives, etc.
So if you want some specific information, you can use that documentation to construct a query that will get it.
If you want all of the information available, you can use the built-in introspection query from GraphQL-JS, listed here: https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js
You can use this information for many different purposes:
Plug it into tools like eslint-plugin-graphql to validate your queries at development time
Build custom documentation browsers
Generate typed code stubs to integrate query results into your Java/Swift apps
I have an ASP.NET Web API Controller that exposes an IQueryable(Of String) - which is a list of descriptions. These fields can be in the order of tens of thousands, thus I use $top and $skip to only get a chunk of it - that works fine.
Now I am trying to filter these results, through the OData substringof('mydesc',Property) filter. As you can see, it requires for me to pass in a Property name on which to filter. However, since I'm returning a list of strings, I don't actually have any properties to filter on.
This causes the server to return errors like
No property or field 'tostring' exists in type 'String' - when called with $filter=substringof('asd',tostring).
If I change the call to $filter=substringof('asd',''), no errors are thrown, but no results either.
My question is, can I somehow format the $filter operator to find substrings within my list of strings, without looking for a property/field, or am I going to have to declare a class with a single property, just to enable filtering?
Things have changed since the last time I answered this. OData V3 has support for querying collection of primitives using '$it'. Asp.net Web API supports this syntax as well. For example, in your controller you can return IQueryable<string> and send a request like
$filter=substring('mydesc', $it) or
$filter=length($it) ge 5
etc. You can also expose collections of other primitives like IQueryable etc.
unfortunately declaring a class with a single property seems to be the only solution that I can think of. OData $filter doesn't have any support for something like the this parameter in C#
another less obvious approach is to expose a computed concatenated value representing the list, substringof could then be used to query the list as a single property value
I am using ADO.Net Data Services and have a Service Operation that ends up returning the results of some linq to entities statements. As a part of those Linq statements there is a .Include("NavProp") to include a sub-object. When running this service operation it doesn't appear to return that expanded Include. Does anyone know either why that is or how to fix that? Is it possible to add a keyword in the call to the service operation to expand that sub-object? (I tried $expand=subObject but that doesn't seem to work - bad request).
I'd like to end up with either:
1.) syntax for a linq statement in a service operation that returns the .Include also (i'm pretty sure this isn't possible)
something like:
(from c in context.MyObj.Include("SubObj")
select c).ToList()
(this works inside the service operation, but doesn't provide the SubObj on the client side)
or
2.) syntax for the service operation request to expand the subObject
something like: http://localhost/MyDataService/MyDataService.svc/ServiceOp1?param1=234$expand=SubObj (note: this doesn't work)
It looks like this is not possible at present (.net 3.5 SP1). Service Operations will only return either primative types or entities. Any other type including custom types or expanded entities cannot be returned from a service operation. To deal with this one must just return the item(s) from the service operation and then if an include/expand is needed on the client side one must call "LoadProperty" for the desired object expansion (note: this means another database hit per LoadProperty call).
Having emailed MS on this issue, the solution is to use the expand query option on the uri of the service operation. For example,
.../<ServiceOperationName>.svc?$expand=<Property1Name>,<Property2Name> ...
Service Operation: GetCustomer
Relationship Property to load: Address
Uri: .../<GetCustomer>.svc?$expand=Address
Hope this helps.