我有两个 ViewModel(产品和零件):
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 Core 查询,该查询返回 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
}
]
}
]
现在,这对于我 .Take(10) 的查询效果很好,尽管看起来很慢,但当我尝试序列化 1727 条记录时,它陷入困境,五分钟的等待甚至无法完成序列化过程。
我尝试使用 Json.Net:
var ret = JsonConvert.SerializeObject(products, new JsonSerializerSettings { Formatting = Formatting.Indented });
我只是决定尝试使用 Json.Net 中的 JsonConvert,因为在我的 Controller 操作中,当尝试返回 JsonResult 时,以下将我的对象转换为 JSON 的代码也存在相同的效率问题:
return Json(products);
我通过 EF Core 获取产品,如下所示:
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 Core 会为您执行查询日志记录。)
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))
。我猜 Entity Framework 正在生成一个 HAVING 子句,但如果您发布生成的 SQL 来优化查询,它会有所帮助。
最后,Select
方法中的一个微优化是更改 Parts 属性获取表达式。
// other properties ...
Parts = pr.Parts.Where(w => w.IsActive).OrderBy(o => o.Name),
// other properties ...
这将阻止您的数据库获取和排序不活动的部分。
关于.net - JSON 序列化需要很长时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43851097/