JSON序列化需要很长的时间

问题描述:

我有两个的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

序列化并不是什么大不了的事,现在很容易注意到你已经添加了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 ... 

这将阻止您的数据库获取和排序非活动部分。