首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

WCF 服務中 LINQ 投影查詢的陷阱與替代方案:QueryView 實現強類型投影

     編輯:關於.NET

LINQ 投影 (select new { ... }) 生成匿名類型,導致無法作為 WCF 服務操作返回類型、無法跨方法邊界傳遞。WCF Data Services 4.0 引入 $select 查詢選項支援投影,但自託管 WCF / RIA Services 仍需強類型方案。本文對比三種方案,重點講解 Entity Framework QueryView (映射視圖) 實現編譯期強類型投影,完美解決「臨時視圖類型」難題。

問題根源:匿名類型無法跨越邊界

// 無法作為服務操作返回類型
public IQueryable<object> GetCustomers()
{
    return ctx.Customers.Select(c => new { c.CustomerID, c.LastName }); // 編譯錯誤
}

方案對比

方案優點缺點適用場景
定義專用 DTO 類強類型、可序列化、可跨層傳遞類爆炸、維護成本高、一次性視圖仍需寫類穩定、復用的投影
WCF Data Services $select無需服務端代碼、客戶端動態投影僅限 OData 端點、客戶端需支援 LINQ to RESTOData 服務、Silverlight/JS 客戶端
EF QueryView (映射視圖)模型級強類型、無新類、可更新、跨 WCF/RIA 通用需手寫 EDMX XML、不支援投影內字符串拼接參數選用表、只讀引用列表、頻繁復用的投影

QueryView 實戰:CustomerNameAndID 參數選用表

1. EDMX 中定義目標實體 (概念模型 CSDL)

<EntityType Name="CustomerNameAndID">
  <Key><PropertyRef Name="CustomerID" /></Key>
  <Property Name="CustomerID" Type="Int32" Nullable="false" />
  <Property Name="FirstName" Type="String" Nullable="false" MaxLength="50" />
  <Property Name="LastName" Type="String" Nullable="false" MaxLength="50" />
</EntityType>

2. 存儲模型 (SSDL) 確認表結構

<EntityType Name="Customer"> ... <Property Name="CustomerID" Type="int" ... /> ... </EntityType>
<EntityContainer Name="ModelStoreContainer"> ... </EntityContainer>

3. 映射規范 (MSL) 中編寫 QueryView (核心步驟)

<EntityContainerMapping ...>
  <EntitySetMapping Name="CustomerNameAndIDs">
    <EntityTypeMapping TypeName="AWModel.CustomerNameAndID">
      <QueryView>
        SELECT VALUE AWModel.CustomerNameAndID(c.CustomerID, c.FirstName, c.LastName)
        FROM ModelStoreContainer.Customer AS c
      </QueryView>
    </EntityTypeMapping>
  </EntitySetMapping>
</EntityContainerMapping>

關鍵點:SELECT VALUE 構造實體,參數順序與屬性順序嚴格對應;不支援 投影內拼接 (c.FirstName + ' ' + c.LastName),需客戶端處理。

使用效果:服務操作直接返回強類型集合

// WCF 服務
public List<CustomerNameAndID> GetCustomerPickList()
{
    using (var ctx = new AWEntities())
    {
        return ctx.CustomerNameAndIDs.OrderBy(c => c.LastName).ToList();
    }
}

// RIA Services 域服務
public IQueryable<RestaurantPickList> GetRestaurantPickList()
{
    return context.RestaurantPickLists; // 同樣受益於 QueryView
}

// WCF Data Services 客戶端
var list = ctx.CustomerNameAndIDs.ToList(); // 無投影代碼

QueryView 進階特性

  • 可更新性:雖為只讀視圖,可通過映射 Insert/Update/Delete 存儲過程實現寫入。
  • 上下文跟蹤:ObjectContext 正常跟蹤實體狀態,SaveChanges 可持久化 (若映射了修改存儲過程)。
  • 外鍵關聯 (EF4+):投影實體保留外鍵屬性,便於編輯場景下綁定關聯。

限制與注意

  1. EDMX 設計器不支援 QueryView,必須手編 XML (右鍵 EDMX → Open With → XML Editor)。
  2. 投影表達式僅支援純列選取、無函數/運算/連接。
  3. 實體集名稱 (CustomerNameAndIDs) 需與 MSL 中 EntitySetMapping Name 一致。

總結

QueryView 將「投影視圖」提升為模型一等公民,消除 DTO 類爆炸,實現編譯期類型安全與跨層傳遞。對於參數選用表、引用數據、只讀報表等高頻投影場景,是比匿名類型與手寫 DTO 更優雅的架構選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved