Calling the right URI with ODATA using ODataClient with Expand - filter

I have two tables which are related to each other and I would like to perform some querying with filters on both tables (one for each)
I am using a controller in c# that looks like this :
var list =
await client.For("T_Project")
.Filter("IsQuote eq false")
.Expand("T_Ref_StatusProject")
.Filter("Final eq false")
.FindEntriesAsync();
Here is the URI that I get with this code :
http://localhost:12494/gp/T_Project?$filter=(IsQuote eq false) and (Final eq false)&$expand=T_Ref_StatusProject
However, I get an error saying bad request. I figure the one I want would look something like
http://localhost:12494/gp/T_Project?$filter=(IsQuote%20eq%20false)&$expand=T_Ref_StatusProject($filter=Final%20eq%20true)
The result is, however, exactly the same as if I didn't put any filter for the expand table.
So I have actually two question. How can I make it work in my c# code and what is the right URL syntax for it. I figure answering the first one will answer the second one.
My UI project (the one with the sample code) have Simple.OData.Client(5.0.0 alpha2) installed (which include Microsoft.Odata.Code (6.15.0)
My API have Microsoft.ASPNet.Odata V5.9.1 installed
Thanks

According to the ODATA documentation filtering on nested properties would look like this:
http://localhost:12494/gp/T_Project?$filter=(IsQuote eq false) and (T_Ref_StatusProject/any(d:d/Final eq false))
See QueryOptions 5.1.1.10.1 any, http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part2-url-conventions/odata-v4.0-errata03-os-part2-url-conventions-complete.html, see also "Addressing Derived Types" in the document which describes the concept in general.
I cannot help you on the first part of your question, as I am not using the C# client. But maybe you can check if the Filter() method accepts a lambda expression, where you can specify an expression that directly corresponds to the expanded entity.

Related

GRAPH API Cannot filter enum

I am trying to filter SSPR results from AAD directoryAudits using:-
https://graph.microsoft.com/beta/auditLogs/directoryAudits?filter=category eq 'SSPR'
This works fine, however if I try to filter on say the result:
result eq success
"result": "success"
I get the error:-
"message": "The string 'Microsoft.AAD.Reporting.operationResult'success'' is not a valid enumeration type constant.",
So I have searched in the metadata and found some appropriate enums, and tried them, but nothing seems to work!
This seems such a simple thing, but I can't seem to work out a way past it.
I'm not sure if it is just this field, or enums in general.
Please help :)
According to the error message the string 'Microsoft.AAD.Reporting.operationResult'success'' is not a valid enumeration type constant, it means that $filter success is not supported.
Per List directoryAudits API, the following attributes are supported by $filter.
But based on my test and you mentioned that category also is supported.
If possible, you could filter the result on the client as workaround.

OData - converting parameter entity set to LINQ

I have an OData URI that works as I want, passing a value for a parameter called gridsize and retrieving the data from Results. This is the URI and it works fine:
http://<webservice>/MULTI_POINT_PARAMParameters(gridsize=0.1m)/Results
I am trying to get the above URI to work using LINQ. I am using an MVC service reference to generate the proxy class. So I tried this LINQ:
var query = (from x in context.MULTI_POINT_PARAMParameters
where
x.gridsize == 0.1M
select x);
However the above LINQ generates this URI, which fails saying "segement not found":
http://<webservice>/MULTI_POINT_PARAMParameters()?$filter=gridsize eq 0.1M}
What I really want LINQ to generate is this, which I know works:
http://<webservice>/MULTI_POINT_PARAMParameters(gridsize=0.1m)/Results
How can I get LINQ to generate the URI I want? I've looked at Linq2rest but could not see how it can help me if I want to explicitly code the LINQ terms myself, rather than have Linq2rest generate "hidden" terms I cannot see.
As far as my knowledge if you want to add filter in OData you have to use "$filter".
if you want to use "MULTI_POINT_PARAMParameters(gridsize=0.1m)" then you might have to use dynamic generation of LINQ.
After dynamic generation your query might look something like this
var query = (from x in context.MULTI_POINT_PARAMParameters(gridsize=0.1m)
select x);
I am just trying to give you a direction to think.Lets see what others have opinion on your question.

MS CRM QueryExpression ConditionExpression w/ CRMBoolean type

I'm using Microsoft's CRM software (4.0) and I'm trying to build a query expression. It works fine with querying only String values, but now I need to include a field that is of type CRMBoolean. I should also mention I'm querying custom entities.
So previously, in my query I would only search by a few fields, but they were all of type String. Now I need to add another ConditionExpression for a CRMBoolean. The type of custom entity I'm searching for has a field called "Condition" - which will either have a value of "true" or "false". In CRM the attribute is defined as a bit, but I didn't think that would make a difference.
Here is my code I'm trying to use to find records that have a condition of "true":
oCondition = New ConditionExpression()
oCondition.AttributeName = "myEntity_condition"
oCondition.Operator = ConditionOperator.Like
Dim bool As New CrmBoolean
bool.Value = True
oCondition.Values = New Object() {bool}
listConditions.Add(oCondition)
I don't get an error, but nothing really happens. The number of records that is returned never changes one way or another. Has anyone done this before?
Thanks in advance!
Instead of putting a CrmBoolean object in the oCondition.Values array, just put a regular true/false boolean. I would also concur with benjynito on changing it to ConditionOperator.Equals instead of Like.
I don't know how the like operator is suppose to behave on a boolean. I wonder if its being ignored. Try ConditionOperator.Equal.

OrderBy("it." + sort) -- Hard coding in LINQ to Entity framework?

I have been trying to use dynamic LINQ to Entity in my application for specifying the OrderBy attribute at runtime. However when using the code as described in the majority of documentation:
var query = context.Customer.OrderBy("Name");
I received the following exception:
System.Data.EntitySqlException: 'Name' could not be resolved in the current scope or context. Make sure that all referenced variables are in scope, that required schemas are loaded, and that namespaces are referenced correctly.
After much searching I found this MSDN page:
http://msdn.microsoft.com/en-us/library/bb358828.aspx
Which included the following code example:
ObjectQuery<Product> productQuery2 = productQuery1.OrderBy("it.ProductID");
This prompted me to change my code to the following:
var query = context.Customer.OrderBy("it.Name");
After this the code works perfectly. Would anyone be able to confirm that this is indeed the correct way to get OrderBy working with LINQ to Entity? I can’t believe that the framework would have been implemented in this way, perhaps I have overlooked something?
Thanks, Matt
The it.Name syntax is ESQL and is indeed specific to the EF. There are good reasons to use this sometimes (e.g., collation specifiers), but it's not what I normally do.
Usually I use standard LINQ expressions:
var query = context.Customer.OrderBy(p => p.Name);
You can also use System.Linq.Dynamic, if you download it from Code Gallery, and then your original query:
var query = context.Customer.OrderBy("Name");
...will work.
No nice way, so far
My answer to this question was to create a stored procedure which has parameter to control sorting.

LINQ multiple where clause

I have a course table which I need to search based on keywords typed in the search box.
Here is a sample query:
SELECT * FROM Courses WHERE
Title LIKE '%word%' OR Title LIKE '%excel%' OR
Contents LIKE '%word%' OR Contents LIKE '%excel%'
How can I convert this in LINQ where LINQ would dynamically generate WHERE statements based on each keywords.
I tried to user PredicateBuilder it works fine as long as the field is VARCHAR. For the "TEXT" fields the quotes are not generated thus causing compiler to give an error message. Here is the SQL generated by PredicateBuilder
SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active],
FROM [dbo].[Courses] AS [t0]
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%)
Notice there is no single Quote for the "Contents" field which is a Text field in the database.
Is there any easy way to build WHERE statement and attach it with query? Does anyone know how I can do this without PredicateBuilder?
Thanks in advance.
Since you are working w/ LINQ I suppose you are working against a LINQ-to-SQL data context right? I don't have a spare DataContext lying around to test this, but this should give you some ideas.
I don't know if it will work against data context though, but most of these are pretty basic stuff (chaining OR operator and Contains method call) so it shouldn't cause problem when the query translates to SQL.
First I create a custom function that would build my predicate:
Func<string, Func<DataItem, bool>> buildKeywordPredicate =
keyword =>
x => x.Title.Contains(keyword)
|| x.Contents.Contains(keyword);
This is a function which takes a single string keyword and then return another function which takes a DataItem and checks it against the keyword.
Basically, if you pass in "Stack", you'll get a predicate: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack").
Next, since there are many possible keywords and you need to chain it with an OR operation, I create another helper function to chain 2 predicates together with an OR
Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
(pred1, pred2) =>
x => pred1(x) || pred2(x);
This function takes 2 predicates and then join them up with an OR operation.
Having those 2 functions, I can then build my where predicate like this:
foreach (var word in keywords) {
filter = filter == null
? buildKeywordPredicate(word)
: buildOrPredicate(filter, buildKeywordPredicate(word));
}
The first line inside the loop basically checks if the filter is null. If it is, then we want a simple keyword filter built for us.
Else if the filter is not null, we need to chain existing filters with an OR operation, so we pass the existing filter and a new keyword filter to buildOrPredicate to do just that.
And then we can now create the WHERE part of the query:
var result = data.Where(filter);
Passing in the complicated predicate we've just built.
I don't know if this will different from using PredicateBuilder but since we are deferring query translation to the LINQ-to-SQL engine, there should not be any problems.
But as I said, I havn't tested it against a real data context, so if there's any problems you can write in the comments.
Here's the console app that I built to test: http://pastebin.com/feb8cc1e
Hope this helps!
EDIT: For a more generic and reusable version which involves properly utilizing the Expression Trees in LINQ, check out Thomas Petricek's blog post: http://tomasp.net/articles/dynamic-linq-queries.aspx
As predicate builder doesn't know the DB type of the property the Contains method is called on, I guess this might be a problem inside linq to sql. Have you tried with a normal query (not with predicate builder) and a TEXT column with Contains?

Resources