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();
我该怎么办?
答
序列化并不是什么大不了的事,现在很容易注意到你已经添加了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 ...
这将阻止您的数据库获取和排序非活动部分。
阅读[问],显示你是如何获得'产品'。 – CodeCaster
你确定这是需要这么长时间的序列化过程吗?另外你可能想在服务器上实现某种分页以避免内存不足。 –
我加了查询,@CodeCaster – crackedcornjimmy