本文章是由機器翻譯。

資料點

WCF 服務中的 LINQ 投影查詢和替代項目

Julie Lerman

下載範例程式碼

在我的本機.NET 使用者群組主持人已撰寫 LINQ 查詢在他的工作階段上個月我出現他詢問訊息時 「 How 嗎我們曾經住不 LINQ? 」「 我不曉得,」 他回覆。

它 ’s,則為 True。 因為它已在 Visual Studio 2008 引入,LINQ 完成了 這類 中如何我們在 Microsoft.NET Framework 中的程式碼的差異。 在 Visual Basic 和 C# 所引入之許多新語言功能搭配它 ’s 的查詢記憶體中的物件和資料來源的一致的問題規劃求解。

其中一個是同時護佑 LINQ ’s 能力和偶爾挫折的來源是它可以專案隨機造形的資料到匿名型別。 當您只需要抓取您的資料的特殊檢視而不需要這個 throwaway 型別的新類別宣告時,匿名型別是很好的解決方案。 LINQ 預測和匿名型別有肯定會將我們 spoiled。 所以為何執行我說他們也可以成為挫折的來源?

如果您以前已使用 LINQ 投射在需要將資料傳給另一種方法的方法 — 或更糟的是,Windows 通訊基礎 (WCF) 服務作業中使用 LINQ 投影 — 您可能會了解。

因為匿名型別 throwaway 類型,它們有沒有宣告,並瞭解只建立所在之方法內。 如果您撰寫查詢以傳回匿名型別的清單,’s 沒有定義方法 ar-gument 說 「 我會傳回一份 … 」 的方法因為有 ’s 沒有地表達 「 … 匿名型別的 」

這裡 ’s 一個 LINQ to 與簡單投射的實體查詢:

var custQuery = from c in context.Customers

                 select new {c.CustomerID, Name=c.LastName.Trim() + 

                 ", " + c.FirstName};

在執行階段 custQuery 變數將實際上會 ObjectQuery <<>f__AnonymousType0 <int,string> >。

var (和替代使用 Visual Basic Dim) 可讓我們取得離開用不需要 (或需要) 地表達此非型別。

若想從方法傳回該查詢的結果只合理的解決方案就是建立類別,以代表正在傳回型別。執行此動作時,不過,將呈現匿名型別 moot 美麗。現在必須撰寫更多的程式碼定義類別和 (可能) 新的專案,以儲存新的類別,請確定各種使用這些類別的組件可以存取它們等等。

直到最近,提供額外的 conundrum 資料服務。順序專案的資料必須在服務中建立自訂的作業、 執行您自己的查詢,然後再將可以解讀的用戶端的預先定義類別的某些型別。

您使用服務時, 有許多案例,您要使用特定的檢視資料而不需付較大的型別移動跨網路傳輸的價格。

其實,除了在您的網域中建立一個額外的型別來滿足這個暫存需要更多的選項。

WCF 資料服務 」 中的新投影功能

.NET Framework 3.5 SP1 的 [資料] 服務更新程式介紹少數強大的功能為 WCF 資料服務也是.NET Framework 4 的一部分。在這些功能之間就是在對資料服務的查詢中使用預測能力。我強烈建議簽出 WCF 資料服務小組部落上所有的 ’s 新 在此更新中blogs.msdn.com/astoriateam/archive/2010/01/27/data-services-update-for-net-3-5-sp1-available-for-download.aspx.

已加入資料服務 URI 語法 $ 選取運算子。它可讓屬性和甚至導覽屬性投射。

這裡 ’s 取得客戶沿著 SalesOrderHeaders 導覽屬性的幾個純量屬性的投射的簡單範例:

http://localhost /DataService.svc/Customers(609)
  $select=CustomerID,LastName,FirstName,SalesOrderHeaders&$expand=
  SalesOrderHeaders

展開運算子強迫結果包含不只是那些訂單,但為每個順序以及資料連結。

圖 1 顯示此查詢的結果。雖然客戶資訊會以綠色醒目提示展開的 SalesOrderHeaders (其中包含僅以單一的順序) 是以黃色反白顯示。


圖 1要求的三個客戶屬性和客戶 ’s SalesOrderHeaders 資料服務查詢投射的結果

LINQ to REST 功能的.NET Framework 和 Silverlight 用戶端 WCF 資料服務的 API 已經更新,以允許估算也:

var projectedCust = (from c in context.Customers

                    where c.CustomerID==609

                    select new {c.CustomerID, c.LastName})

                    .FirstOrDefault();

ProjectedCust 現在是我可以在我的用戶端應用程式中使用匿名型別。

’s 也可能會成已知的實體類型的專案,並在某些情況下 [DataContext 可以追蹤用戶端所做的變更及這些變更可保存回透過服務 ’s SaveChanges 方法。是注意任何遺漏的屬性會取得填入其預設值 (或 null (如果 ’re 可為 Null),而且會保留在資料庫中。

啟用來自 EDM 預計強式型別

如果您使用實體架構實體資料模型 (EDM),’s 一個便利方法,可避免當您需要傳遞超出方法以建立與匿名型別被卡住。

EDM 有稱為 QueryView 的對應。我指到這樣的許多用戶端在過去之前至資料服務投射支援。不只做它解決問題得很好的資料服務但自訂 WCF 服務和 RIA 服務也。

什麼是一個 QueryView?它 ’s 一種特殊類型的對應 Entity Framework 中繼資料中。通常,將實體的屬性對應到資料庫資料表或檢視資料行,如述儲存區模型 — 存放區結構描述定義語言 (SSDL) — 中繼資料中 所示的圖 2.


圖 2將資料表的資料行對應到實體內容直接

一個 QueryView 不過,可讓您建立一個檢視透過那些 SSDL 資料表資料行,而不是直接要它們的對應。有許多原因来使用一個 QueryView。有些範例包括:為已閱讀-只,以便篩選實體亦條件式的方式公開您的實體對應並不允許,或提供的資料表格從資料庫的不同檢視。

它 ’s 我將著重於另一個方法您經常發現自己將往回投影在您的應用程式中的匿名型別是這些用途的最後一個。一個範例是挑選清單。為什麼傳回一個下拉式的 ID 和客戶 ’s 名稱所需的整個客戶類型?

建置一個 QueryView

在建立一個 QueryView 之前您必須建立實體模型,代表的檢視希望的圖案中 — 比方說 CustomerNameAndID 實體。

但您 can’t 此實體直接對應到 SSDL 中的 [客戶] 表格。將客戶實體和 CustomerNameAndID 實體對應到資料表 ’s [客戶編號] 資料行,會產生衝突。

改,就像您可以在您的資料庫中建立資料表的檢視,您可以直接在中繼資料中建立 SSDL 客戶的檢視。一個 QueryView 逐字是一個 Entity SQL 透過 [SSDL 的運算式。它 ’s 對應規格語言 (MSL) 中繼資料模型的一部份。要建立 [QueryView,讓您需要在 XML 中直接輸入沒有設計工具支援。

因為您對應至它 ’s 看到什麼,是個不錯的作法看起來就像資料表的存放區結構描述。圖 3 列出看起來類似客戶實體在概念性模型 ’s 中繼資料提供者的資料型別使用以外的客戶資料庫表格 SSDL 的描述。

圖 3資料庫的 [客戶] 表格的 SSDL 描述

<EntityType Name="Customer">

  <Key>

    <PropertyRef Name="CustomerID" />

  </Key>

  <Property Name="CustomerID" Type="int" Nullable="false"

            StoreGeneratedPattern="Identity" />

  <Property Name="Title" Type="nvarchar" MaxLength="8" />

  <Property Name="FirstName" Type="nvarchar" Nullable="false" 

            MaxLength="50" />

  <Property Name="MiddleName" Type="nvarchar" MaxLength="50" />

  <Property Name="LastName" Type="nvarchar" Nullable="false" 

            MaxLength="50" />

  <Property Name="Suffix" Type="nvarchar" MaxLength="10" />

  <Property Name="CompanyName" Type="nvarchar" MaxLength="128" />

  <Property Name="SalesPerson" Type="nvarchar" MaxLength="256" />

  <Property Name="EmailAddress" Type="nvarchar" MaxLength="50" />

  <Property Name="Phone" Type="nvarchar" MaxLength="25" />

  <Property Name="ModifiedDate" Type="datetime" Nullable="false" />

  <Property Name="TimeStamp" Type="timestamp" Nullable="false"

            StoreGeneratedPattern="Computed" />

</EntityType>

對於 [QueryView 另一個重要的項目將會存放區結構描述 ’s namespace ModelStoreContainer。 現在您有建構 QueryView 運算式的必要部分。 這裡 ’s QueryView,該專案三個需要來自 [SSDL 欄位到我建立模型中的 CustomerNameAndID 實體:

SELECT VALUE AWModel.CustomerNameAndID(c.CustomerID, c.FirstName, 

        c.LastName) FROM ModelStoreContainer.Customer as c

正在轉譯實體 SQL 英文:「 查詢存放區結構描述中的客戶、 拉出這三個資料行並提供它們回我的電腦視為 CustomerNameAndID 實體 」。AWModel 是概念性模型 ’s 實體容器的命名空間。您才能使用運算式中參考的概念性結構描述定義語言 (CSDL) 和 SSDL 型別的強型別的名稱。

只要投射 (一個整數、 字串和字串) 結果相符之結構描述的目標實體,對應會成功。我試著使用函式和串連內投射 — 例如,(c.CustomerID、 c.FirstName + c.LastName)—but 這失敗,錯誤訊息指出不允許函式。因此我強制使用名字] 和 [姓氏] 屬性,並讓用戶端處理的串連。

將 [QueryView 放入中繼資料

您必須放置 QueryView 運算式內的內部中繼資料中 EntityContainerMapping 進入的實體 EntitySetMapping 項目。圖 4 顯示 (以黃色反白顯示) 此 QueryView 中我 EDMX 檔的原始 XML。

圖 4在 [對應] 區段 QueryView

現在我 CustomerNameAndID 是我模型的一部份,並且將可供任何消費者。而且沒有 [QueryView 到另一個優點。即使這個 QueryView 的目標是要建立唯讀參考清單,您還可以更新使用 QueryViews 對應的實體。內容會追蹤 CustomerNameAndID 物件的變更。雖然 Entity Framework 並不能自動產生插入、 更新和刪除此實體的指令,您可以將預存程序對應到它。

reaping [QueryView 的優點

既然您在模型中有 [QueryView,don’t 需要預測或擷取資料的這些檢視的匿名型別而定。在 WCF Data Services CustomerNameAndIDs 成為到,對查詢有效的實體集如下所示:

List<CustomerNameAndID> custPickList = 

  context.CustomerNameAndIDs.ToList();

沒有雜亂的估算。 更好,您可以現在就可以傳回這個強型別的物件,而應用程式和專案中定義新的型別,在其中您自訂 WCF 服務 」 中建立服務作業。

public List<CustomerNameAndID> GetCustomerPickList()

    {

      using (var context = new AWEntities())

      {

        return context.CustomerNameAndIDs.OrderBy(

          c => c.LastName).ToList();

      }

    }

因為的限制防止我們串連 [QueryView 中的第一個和最後一個名稱,它 ’s 開發人員取用服務,才能執行此串連上其結束。

WCF RIA 服務也可以從 [QueryView 獲得好處。 若要公開一個方法以從您的網域服務擷取餐廳挑選清單。 而不需要在網域服務,來代表預計的內容中建立額外的類別,此 RestaurantPickList 實體是由模型可讓您輕鬆地提供這項資料中 QueryView 支援:

public IQueryable<RestaurantPickList> GetRestaurantPickList()

    {

      return context.RestaurantPickLists;

    }

QueryViews 或預測 — 我們有涵蓋您

擁有專案檢視能夠透過您的資料型別是在查詢,極大好處,’s 絕佳除了 WCF 資料服務。甚至因此但有時也會時具有存取這些檢視,而不必專案和而不必擔心共用該結果會簡化一些程式碼撰寫工作。

一個最後一個注意事項:外部索引鍵 Entity Framework.NET Framework 4 版中引入,QueryView 挑選清單產生甚至更多意義因為您可以傳回唯讀的實體,只是使用其內容來更新編輯的實體中的外部索引鍵屬性。  

Julie Lerman* 是一個 Microsoft MVP 在.NET 輔導員及居住在 Vermont 丘陵的顧問。您可以找到她資料存取和其他 Microsoft.NET 主題在使用者群組和世界各地的研討會上呈現。在 Lerman 部落格thedatafarm.com/blog 是高度 acclaimed 書籍 「 發展 Entity Framework 」 O’Reilly 媒體,2009年作者。依照她 Twitter 上:julielerman.*

多虧給來檢閱這份文件的技術專家下列:Alex James