逐步解說:使用型別提供者存取 OData 服務 (F#)
OData (指 Open Data Protocol,開放式資料通訊協定) 是透過網際網路傳輸資料的通訊協定。許多資料提供者會發行 OData Web 服務讓他們的資料可以公開供他人存取。您可以從任何 OData 來源的資料在 F# 3.0 使用由 ODataService 型別提供者所產生的資料型別。如需 Introducing OData 的詳細資訊,請參閱 GDI+。
這個逐步解說會示範如何使用 ODataService F# 型別的提供者產生 OData 服務的用戶端類型和查詢服務提供的資料輸入。
這個逐步解說將說明下列工作,您應該在這個逐步解說的這個順序執行才會成功:
設定 OData 服務的用戶端專案
存取 OData 型別
查詢 OData 服務
驗證 OData 要求
設定 OData 服務的用戶端專案
在這個步驟中,您會為使用 OData 型別提供者設定一個專案。
設定 OData 服務的用戶端專案
開啟 F# 主控台應用程式專案,然後將 System.Data.Services.Client Framework 組件的參考。
在擴充功能下,新增FSharp.Data.TypeProviders 組件的參照。
存取 OData 型別
在這個步驟中,您會建立針對 OData 服務提供存取類型和資料的型別提供者。
存取 OData 型別
在程式碼編輯器中,開啟 F# 原始程式檔,然後輸入下列程式碼。
open Microsoft.FSharp.Data.TypeProviders type Northwind = ODataService<"http://services.odata.org/Northwind/Northwind.svc/"> let db = Northwind.GetDataContext() let fullContext = Northwind.ServiceTypes.NorthwindEntities()
在此範例中,您調用 F# 型別提供者及指示它根據你所指定的OData URI創造一組型別。兩個物件有包含有關資料的資訊,一個是簡化的資料內容,在db 的範例中。這個物件只包含與資料庫相關,其中包括資料表或摘要型別的資料型別。其他物件,如下列範例所 fullContext ,是 DataContext 的執行個體並且包含許多其他屬性、方法和事件。
查詢 OData 服務
在這個步驟中,您使用 F# 查詢運算式查詢 OData 服務。
查詢 OData 服務
現在您已經設定了型別提供者,您可以查詢 OData 服務。
OData 只支援可用查詢作業的子集。支援下列作業和其對應的關鍵字:
投影(select)
篩選 (where,透過使用字串和日期作業)。
分頁 (skip, take)
排序 (orderBy, thenBy)
AddQueryOption 和 Expand,是 OData 特定的作業
如需詳細資訊,請參閱LINQ Considerations。
如果您需要摘要或資料表中的所有項目,請使用查詢運算式最簡單的形式,如下列程式碼所示:
query { for customer in db.Customers do select customer } |> Seq.iter (fun customer -> printfn "ID: %s\nCompany: %s" customer.CustomerID customer.CompanyName printfn "Contact: %s\nAddress: %s" customer.ContactName customer.Address printfn " %s, %s %s" customer.City customer.Region customer.PostalCode printfn "%s\n" customer.Phone)
您可以使用在 SELECT 關鍵字之後的tuple來指定您想要欄位或資料行。
query { for cat in db.Categories do select (cat.CategoryID, cat.CategoryName, cat.Description) } |> Seq.iter (fun (id, name, description) -> printfn "ID: %d\nCategory: %s\nDescription: %s\n" id name description)
您可以使用 where 子句來指定條件。
query { for employee in db.Employees do where (employee.EmployeeID = 9) select employee } |> Seq.iter (fun employee -> printfn "Name: %s ID: %d" (employee.FirstName + " " + employee.LastName) (employee.EmployeeID))
您可以使用Contains 方法來指定子字串條件查詢。下列查詢會回傳具有「Cook」在其名稱的所有產品。同時也請注意使用 GetValueOrDefault。UnitPrice 是可為 Null 值,因此,您必須使用 Value 屬性來取得或值,或者您必須呼叫 GetValueOrDefault。
query { for product in db.Products do where (product.ProductName.Contains("Chef")) select product } |> Seq.iter (fun product -> printfn "ID: %d Product: %s" product.ProductID product.ProductName printfn "Price: %M\n" (product.UnitPrice.GetValueOrDefault()))
使用 EndsWith 方法指定某個以特定子字串結束的字串。
query { for product in db.Products do where (product.ProductName.EndsWith("u")) select product } |> Seq.iter (fun product -> printfn "ID: %d Product: %s" product.ProductID product.ProductName printfn "Price: %M\n" (product.UnitPrice.GetValueOrDefault()))
您可以使用 && 運算子來合併where子句中的條件。
// Open this module to use the nullable operators ?> and ?<. open Microsoft.FSharp.Linq.NullableOperators let salesIn1997 = query { for sales in db.Category_Sales_for_1997 do where (sales.CategorySales ?> 50000.00M && sales.CategorySales ?< 60000.0M) select sales } salesIn1997 |> Seq.iter (fun sales -> printfn "Category: %s Sales: %M" sales.CategoryName (sales.CategorySales.GetValueOrDefault()))
?> 和 ?<運算子是可為 Null 的運算子。您可以使用整套可為 Null 的等號運算子和比較運算子。如需詳細資訊,請參閱Linq.NullableOperators 模組 (F#)。
使用 sortBy 查詢運算子來指定順序,和使用 thenBy 指定另一個層級的排序。同時記得使用在查詢的選取部分的 tuple。因此,查詢中具有 tuple 做為元素型別。
printfn "Freight for some orders: " query { for order in db.Orders do sortBy (order.OrderDate.Value) thenBy (order.OrderID) select (order.OrderDate, order.OrderID, order.Customer.CompanyName) } |> Seq.iter (fun (orderDate, orderID, company) -> printfn "OrderDate: %s" (orderDate.GetValueOrDefault().ToString()) printfn "OrderID: %d Company: %s\n" orderID company)
您可以使用skip運算子來略過指定的記錄數目,以及使用take運算子回傳指定的一些記錄。如此一來,您就可以實作在資料輸入的分頁。
printfn "Get the first page of 2 employees." query { for employee in db.Employees do take 2 select employee } |> Seq.iter (fun employee -> printfn "Name: %s ID: %d" (employee.FirstName + " " + employee.LastName) (employee.EmployeeID)) printfn "Get the next 2 employees." query { for employee in db.Employees do skip 2 take 2 select employee } |> Seq.iter (fun employee -> printfn "Name: %s ID: %d" (employee.FirstName + " " + employee.LastName) (employee.EmployeeID))
驗證 OData 要求
每個 OData 查詢被翻譯成特定 OData 所要求的 URI。為了偵錯,您可以加入事件處理程序在完整的資料內容物件中的 SendingRequest 事件來驗證 URI。
驗證 OData 要求
若要驗證 OData 要求 URI,請使用下列程式碼:
// The DataContext property returns the full data context. db.DataContext.SendingRequest.Add (fun eventArgs -> printfn "Requesting %A" eventArgs.Request.RequestUri)
上述程式碼的輸出是:
要求 http://services.odata.org/Northwind/Northwind.svc/ Orders()? $orderby=ShippedDate&$select=OrderID ShippedDate,