2017-05-08 169 views
1

我有兩個的ViewModels(產品和部分):JSON序列化需要很長的時間

public class ProductViewModel 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public string Description { get; set; }  

    public bool IsActive { get; set; } 

    public IEnumerable<PartViewModel> Parts { get; set; } 
} 

public class PartViewModel 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public bool IsActive { get; set; } 
} 

我運行一個EF核心查詢,返回1727級的產品,每個產品至少1個部分。對這些1回的一個例子是序列化到JSON這樣:

[ 
    { 
     "Id":8761, 
     "Name":"Product Name 1", 
     "Description":"This is a product", 
     "IsActive":true, 
     "Parts":[ 
     { 
      "Id":103767, 
      "Name":"Name 1" 
      "IsActive":true 
     }, 
     { 
      "Id":156436, 
      "Name":"Name 2", 
      "IsActive":true 
     }, 
     { 
      "Id":109436, 
      "Name":"Name 3", 
      "IsActive":true 
     } 
     ] 
    } 
] 

現在,這個工程很好地詢問我在那裏。取(10),雖然看似緩慢,但是當我嘗試和序列化1727記錄,它陷入泥潭,五分鐘的等待甚至不能完成序列化過程。

我嘗試使用Json.Net這樣:

var ret = JsonConvert.SerializeObject(products, new JsonSerializerSettings { Formatting = Formatting.Indented }); 

我才決定嘗試從Json.Net使用JsonConvert,因爲,在我的控制器動作,試圖返回一個JsonResult,下面的代碼時,我的對象轉換爲JSON有同樣的效率問題:

return Json(products); 

我通過EF核心拿到產品本身:

var products = _context.Products.OrderBy(o => o.Name).Where(w => w.IsActive //all products are active 
      && (w.Parts.Count(c => c.IsActive) > 0)) //remove parts that are 
      .Select(pr => new ProductViewModel 
      { 
       Id = pr.Id, 
       Name = pr.Name, 
       Description = pr.Description, 
       IsActive = pr.IsActive, 
       Parts = pr.Parts.OrderBy(o => o.Name).Where(w => w.IsActive) //all parts are active 
       .Select(prt => new PartViewModel 
       { 
        Id = prt.Id, 
        Name = prt.Name, 
        IsActive = prt.IsActive, 
       }) 
      }).ToList(); 

我該怎麼辦?

+1

閱讀[問],顯示你是如何獲得'產品'。 – CodeCaster

+1

你確定這是需要這麼長時間的序列化過程嗎?另外你可能想在服務器上實現某種分頁以避免內存不足。 –

+0

我加了查詢,@CodeCaster – crackedcornjimmy

回答

1

序列化並不是什麼大不了的事,現在很容易注意到你已經添加了LINQ查詢,問題在於SQL Entity Framework將由它產生的糟糕的問題。

首先,您應該使用熱切加載加入您的產品表與零件表。您只需添加一個Include方法調用即可完成此操作。

_context.Products.Include(p => p.Parts) 

如果沒有這樣做,查詢實際上是在執行N + 1個查詢。您應該使用一個簡單的技巧來查看您的查詢正在執行的實際SQL查詢,將此代碼添加到您的DbContext。 (如果您正在使用EF6只能這樣做,EF核心確實查詢記錄你的。)

public YourDBContext() 
{ 
    #if DEBUG 
    this.Database.Log = msg => 
    { 
     Debugger.Log(1, "ALL", "EF DB SQL: " + msg + Environment.NewLine); 
    }; 
    #endif 
} 

另一個條件是在做查詢多久就是.Where(w => w.IsActive && (w.Parts.Count(c => c.IsActive) > 0))。我猜實體框架正在生成一個HAVING子句,但如果您發佈生成的SQL來優化查詢,它將會有所幫助。

最後,您的Select方法中的微優化將是通過改變Parts屬性獲取表達式。

// other properties ... 
Parts = pr.Parts.Where(w => w.IsActive).OrderBy(o => o.Name), 
// other properties ... 

這將阻止您的數據庫獲取和排序非活動部分。