使用 LINQ 对数据库的主表进行多次查询

Make multiple queries to master tables of database using LINQ

我正在使用 Entity framework 来管理所有数据库操作。

在我的应用程序的一个特定屏幕中,我需要从许多彼此不相关的主 table 中获取数据。在 c# 代码中,如果我分别查询每个 table,这将花费大量时间和超过 10 个无法合并的查询。

是否有一个选项,我可以将它们组合起来进行单个数据库调用,但仍继续使用 linq。

目前我在做

 var master1=await (from p in context.Master1
             select p).ToListAsync()

 var master2=await (from p in context.Master2
             select p).ToListAsync()

 var master3=await (from p in context.Master3
             select p).ToListAsync()

有什么替代方案?

var master1 = (from p in context.Master1
         select p).ToListAsync()

var master2 = (from p in context.Master2
         select p).ToListAsync()

var master3 = (from p in context.Master3
         select p).ToListAsync()

await Task.WhenAll(master1, master2, master3);

这不会是单个数据库调用,但可以让他们查询数据而无需等待上一条语句。

只有当所有任务都完成时,代码才会继续经过 WhenAll

第一步是将数据检索抓取到只有必要的部分。调用查询 10 个不相关的表听起来是个糟糕的设计。如果这是您获取 10 倍查找的情况,请考虑重构设计,以便在页面加载时以异步方式(即 Ajax)请求这些请求,而不是一次全部请求。

就加载数据而言,利用投影而不是获取实体。通常当我看到这样的代码时,我首先要寻找的是延迟加载惩罚。在这种情况下,我会看到一些无辜的东西:

var viewModel = new SearchViewModel();

var products = await context.Products.ToListAsync();
viewModel.Products = products;

// ... repeat for other lookups...

return View(viewModel);

这会发出危险信号。

  1. 序列化实体将“触及”导航属性,导致延迟加载命中。
  2. 即使没有导航属性,我们是否需要实体中的所有字段?
  3. async 不是性能灵丹妙药。

对于项目 1 和 2: 将数据加载到视图 return 时,利用投影来避免延迟加载意外,并最大限度地减少从数据库和客户端传输的数据量。延迟加载会使服务器调用慢得离谱,而个别查询调试和 运行s 很快,但在页面返回之前您要等待很多秒甚至几分钟。在数据库上连接 SQL Profiler 将显示,在该方法执行后,数百甚至数千个额外的查询正在访问数据库,超出您最初调用的 10 个左右。这是序列化程序“接触”导航属性,它比您预先加载所有数据要慢很多。这些问题的解决方案是投影:

var viewModel = new SearchViewModel();

var products = await context.Products
    .Select(x => new ProductSummaryViewModel
    {
        ProductId = x.ProductId,
        Name = x.Name
    }).ToListAsync();
viewModel.Products = products;

// ... repeat for other lookups...

return View(viewModel);

您可以通过利用 Automapper 进一步简化此操作,它是 ProjectTo 方法而不是与 EF 的 IQueryable 一起使用的 Select 方法。 Projection 避免延迟加载意外并构建仅 return 您需要的数据的查询。

对于第 3 点:async 不会使操作/调用更快,如果有的话,它会使它们稍微慢一些。它所做的是让您的服务器代码在忙于获取更大的操作时响应更快。我经常看到代码的结构就好像 async 是一个全有或全无的决定。它有它的用途,但在它可以提供最大好处的地方应该谨慎使用。通过 ID 获取小集合或单个记录根本不会从异步生成中受益。如果一个操作不超过 250 毫秒 运行,并且不会在大规模多核微服务服务器上以非常高的频率被调用,老实说我不会费心引入 [= =12=].

最终归结为确保您只查询绝对需要的数据,然后寻找进一步的优化或重组调用(即 Ajax,或分解您的 UI更原子化而不是一个屏幕上的所有内容)如果仍然存在响应障碍。