Search code examples
linqwcf-data-servicesodatawindows-store-apps

How to use $filter in OData query


I have a problem consuming an OData-service in a Windows 8 store application.

If I do this:

IEnumerable<vw_mobSurveyor> lstSurveyors =
    await ((DataServiceQuery<vw_mobSurveyor>)ODataContext.vw_mobSurveyor
        .AddQueryOption("$filter", "intSurveyorID eq " + intID.ToString()))
        .ExecuteAsync("GetByID").ConfigureAwait(false);

it works and the end of the URI is: /vw_mobSurveyor?$filter=intSurveyorID eq 1. This URI also works if I try it in a browser, so all is well.

But if I do :

IEnumerable<vw_mobSurveyor> lstSurveyors = 
    await ((DataServiceQuery<vw_mobSurveyor>)ODataContext.vw_mobSurveyor
        .Where(s => s.intSurveyorID == intID))
        .ExecuteAsync("GetByID").ConfigureAwait(false);

This fails with a Client Internal Error 4. It produces a different ending to the URI: /vw_mobSurveyor(2) This URI fails when I try it in a browser, and that is why it fails when the code generates it.

I have read these two should be equivalent in the produced URI: http://msdn.microsoft.com/en-us/library/ee622463.aspx#filtering.

As I would like to pass a Linq expression in future, so I need to get the second version to work. So how do I force the second version to use $filter so it works?

Update : Fiddler output for working code using $filter

HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 1057
Content-Type: application/atom+xml;type=feed;charset=utf-8
Server: Microsoft-IIS/7.0
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 18 Jan 2013 11:35:34 GMT

<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="http://MYSERVER/TESTAPP%20V1/DataService.svc/"
xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor</id>
  <title type="text">vw_mobSurveyor</title>
  <updated>2013-01-18T11:35:34Z</updated>
  <link rel="self" title="vw_mobSurveyor" href="vw_mobSurveyor" />
  <entry>
    <id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor(2)</id>
    <category term="SurveyProModel.vw_mobSurveyor" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
    <link rel="edit" title="vw_mobSurveyor" href="vw_mobSurveyor(2)" />
    <title />
    <updated>2013-01-18T11:35:34Z</updated>
    <author>
      <name />
    </author>
    <content type="application/xml">
      <m:properties>
        <d:intSurveyorID m:type="Edm.Int32">2</d:intSurveyorID>
        <d:vchName>Bob Green 2</d:vchName>
        <d:vchStatus>Surveyor</d:vchStatus>
      </m:properties>
    </content>
  </entry>
</feed>

Update : Fiddler output for failing code

HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Length: 824
Content-Type: application/atom+xml;type=entry;charset=utf-8
Server: Microsoft-IIS/7.0
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 18 Jan 2013 11:33:30 GMT

<?xml version="1.0" encoding="utf-8"?>
<entry xml:base="http://MYSERVER/TESTAPP%20V1/DataService.svc/"
xmlns="http://www.w3.org/2005/Atom"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <id>http://MYSERVER/TESTAPP%20V1/DataService.svc/vw_mobSurveyor(2)</id>
  <category term="SurveyProModel.vw_mobSurveyor" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <link rel="edit" title="vw_mobSurveyor" href="vw_mobSurveyor(2)" />
  <title />
  <updated>2013-01-18T11:33:30Z</updated>
  <author>
    <name />
  </author>
  <content type="application/xml">
    <m:properties>
      <d:intSurveyorID m:type="Edm.Int32">2</d:intSurveyorID>
      <d:vchName>Bob Green 2</d:vchName>
      <d:vchStatus>Surveyor</d:vchStatus>
    </m:properties>
  </content>
</entry>

Solution

  • This seems like a bug in the WCF Data Services client.

    At first glance, I don't see any issues in the Fiddler traces you provided, but I'll try to reproduce this on my end and I'll file an internal bug for this. If you have a full stack trace of the error, that would be very helpful.

    Just to note: the LINQ-to-URI translation bit is doing the correct thing here. If a .Where clause is only checking the key value of an entity, we optimize the query by directly looking up the entity by its key (i.e., ../vw_mobSurveyor(2)) instead of using the $filter mechanism. This will result in an entry response payload instead of a feed, which matches what you got from Fiddler.

    And to answer your original question, you could force the LINQ translator to use $filter by making the predicate involve anything other than the just the entity key. For example, you could do something like:

    .Where(s => s.intSurveyorID == intID && true)
    

    This is obviously a hack, but it should work. Ideally, we'll find and fix this bug and you can then use a more normal-looking Where clause :).