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

Entity Framework 查詢匿名物件導致跨域存取問題的解決方案

     編輯:關於.NET

問題背景

使用 Entity Framework (EF) 查詢時,為了效能常只選取所需欄位,透過匿名型別或自訂 DTO 投影。但若直接回傳 IQueryable<匿名型別> 給上層(如 Web API、WCF、跨專案呼叫),會因匿名型別編譯器產生的內部型別不可跨組件存取,導致序列化失敗或執行時異常。

場景重現

// 實體類別
public class Category {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

// 查詢僅需 Id、Name
var data = from c in context.Categories
           select new { cId = c.Id, cName = c.Name }; // 匿名型別

// 直接回傳 IQueryable<匿名型別> 給跨域呼叫者 → 爆炸

解決方案對比

方案一:定義具名 DTO 型別(推薦)

建立對應的 DTO 類別,查詢時投影至具名型別:

public class CategoryView {
    public int Id { get; set; }
    public string Name { get; set; }
}

// 查詢
var data = from c in context.Categories
           select new CategoryView { Id = c.Id, Name = c.Name };

// 回傳型別可為 IQueryable<CategoryView> 或 List<CategoryView>
return data.ToList();

優點:型別公開、可序列化、跨組件安全、支援 Swagger/OpenAPI 文件產生。
缺點:需維護額外類別檔案。

方案二:動態型別 ExpandoObject(.NET 4.0+)

var data = from c in context.Categories
           select new { c.Id, c.Name };

var list = new List<dynamic>();
foreach (var item in data) {
    dynamic dto = new ExpandoObject();
    dto.Id = item.Id;
    dto.Name = item.Name;
    list.Add(dto);
}
return list;

優點:無需預先定義類別。
缺點:動態型別效能稍差、無靜態型別檢查、文件生成困難。

方案三:Tuple / ValueTuple (C# 7.0+)

var data = from c in context.Categories
           select new { c.Id, c.Name };

var list = data.AsEnumerable()
               .Select(x => (Id: x.Id, Name: x.Name))
               .ToList();
return list;

優點:語法簡潔、具名元素、可序列化。
缺點:舊版 .NET 不支援、跨語言互通性較弱。

方案四:投影至 Dictionary<string, object>

var list = data.AsEnumerable()
               .Select(x => new Dictionary<string, object> {
                   ["Id"] = x.Id,
                   ["Name"] = x.Name
               })
               .ToList();

適用場景:極度動態欄位需求,但序列化體積較大。

最佳實踐建議

  1. 預設採用具名 DTO:建立 ViewModels 或 Dtos 資料夾集中管理,利於維護與團隊協作。
  2. 搭配 AutoMapper:ProjectTo<CategoryView>() 直接在 SQL 層面投影,避免載入完整實體再映射。
  3. Web API 回傳 IHttpActionResult / ActionResult<T>:配合具名 DTO 可自動產生 OpenAPI 規格。
  4. 避免在 Repository 層回傳匿名型別:Repository 應回傳具名型別或 IQueryable<Entity>,投影邏輯下沉至 Service/Controller 層。

總結

EF 查詢匿名物件雖便利,但跨組件/跨域序列化會失敗。定義具名 DTO 是最穩健、可維護的解法,配合 AutoMapper ProjectTo 可兼顧效能與整潔架構。

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