Code Snippet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#if INTERACTIVE
#r "System.Data.Services.Client"
#r "FSharp.Data.TypeProviders"
#endif

open System
open System.Net
open System.Data.Services.Client
open Microsoft.FSharp.Data

[<Literal>]
let url = @"https://demo.crm4.dynamics.com/XRMServices/2011/OrganizationData.svc/"

[<Literal>] // "%TMP%/odata/OrganizationData.csdl"
let csdl = __SOURCE_DIRECTORY__  + @"/odata/OrganizationData.csdl" 

type Xrm = 
    TypeProviders.ODataService<
        ServiceUri = url,
        LocalSchemaFile = csdl,
        ForceUpdate = false>

let ctx = Xrm.GetDataContext()

// To be used when writing JavaScript with OData
ctx.DataContext.SendingRequest.Add (
    fun eventArgs -> printfn "-Url: %A" eventArgs.Request.RequestUri)
ctx.DataContext.SendingRequest.Add (
    fun eventArgs -> printfn "-Query: %s" eventArgs.Request.RequestUri.Query)

// Remember to "pipe" to a Sequence, in order to evaluate the Linq Query:
query { for a in ctx.AccountSet do
        where (a.AccountNumber = "42")
        select (a.AccountNumber, a.AccountId)
        skip 5
        take 1} 
|> Seq.map id

Code output:

val url : string =
  "https:demo.crm4.dynamics.com/XRMServices/2011/OrganizationData.svc/"
val csdl : string =
  "C:\Users\rsm\AppData\Local\Temp\odata\OrganizationData.csdl"
type Xrm =
  class
    static member GetDataContext : unit -> Xrm.ServiceTypes.SimpleDataContextTypes.demoContext
     + 1 overload
    nested type ServiceTypes
  end
val ctx : Xrm.ServiceTypes.SimpleDataContextTypes.demoContext
val it : unit = ()
-Uri: https:demo.crm4.dynamics.com/XRMServices/2011/OrganizationData.svc/AccountSet()?$filter=AccountNumber eq '42'&$skip=5&$top=1&$select=AccountNumber,AccountId
-Query: $filter=AccountNumber eq '42'&$skip=5&$top=1&$select=AccountNumber,AccountId
val it : seq<string * Guid> = seq []

Remark:

The reason LocalSchemaFile = csdl and ForceUpdate = false are set to static values are because Microsoft still doesn’t allow us to use OData from a server side context (we still need to login to CRM Online with a browser that supports JavaScript). If anybody have a hint on how to access the CSDL service from a .NET application, please write a comment below.

The point is that even though there is no data returned in the .NET application from CRM Online, it doesn’t matter as we just want to use the queries (nicely written in Linq with intellisense and type-safety) outputted from fun eventArgs -> printfn "-Query: %s" eventArgs.Request.RequestUri.Query for our JavaScript code in combination with the official SDK.REST.js library:

1
2
3
4
5
6
7
8
9
SDK.REST.retrieveMultipleRecords(
  "Account",
  "$filter=AccountNumber eq '42'&$skip=5&$top=1&$select=AccountNumber,AccountId", // query
  function (results) {
    // Do stuff
  },
  errorHandler,
  onCompleteHandler
);

The current way it’s done (and built on @deprecated technologies) is just not very handy (and has never been) as it requires to expand your current CRM tenant with a 3rd party managed solution:

CRM 2011 OData Query Designer

References: