c# - Entity Framework - 为集合中的成员加载特定的导航属性

标签 c# entity-framework linq linq-to-entities

我发现了与使用 .Include 等加载相关的各种问题,但似乎 SQL 形状查询到一个巨大的连接,这意味着如果我正在获取客户信息,并且该客户拥有 1000 件商品,而我拥有

context.Customers.Include(c=> c.Inventory).Where(c=>c.ID == id); 
//side note, WHY can't I use .Find() after Include?

我将获得 1000 行相同的客户信息以及商品信息,而不是多表集中的 1 条客户记录和 1000 件商品。这看起来效率很低,并且会导致一些非常慢的查询。

所以如果我有一组客户:

//get all customers in TX
var texasCustomers = context.Customers.Where(c=> c.State == "TX"); 

我想在导出到 XLSX 时循环遍历它们:

foreach (var c in texasCustomers) {
  //compile row per item SKU
  foreach(var sku in c.Inventory.GroupBy(i=>i.SKU)) {
    xlsx.SetCellValue(row, col, c.Name);
    //output more customer info here
    xlsx.SetCellValue(row, col, sku.Key);
    xlsx.SetCellValue(row, col, sku.Sum(i=>i.Quantity));
  }
}

这会生成对每个客户的“库存”表的查询。这是一个快速查询,但是当您执行 SAME 查询 1000 次时,它会变得非常慢。

所以我做了这样的事情:

//get customer key
var customerids = texasCustomers.Select(c=> c.ID).ToArray();
var inventories = context.Inventories.Where(i=> customerids.Contains(i.CustomerID)).ToList();

...现在我的导出循环看起来更像这样...第一个示例中对 nav 属性进行操作的内部循环变成了针对预建 list 对象列表的内存中 linq 过滤器:

foreach (var c in texasCustomers) {
  //compile row per item SKU
  foreach(var sku in inventories.Where(i=> i.CustomerID == c.ID)) { 
    xlsx.SetCellValue(row, col, c.Name);
    //output more customer info and then the sku info
    xlsx.SetCellValue(row, col, sku.Key);
    xlsx.SetCellValue(row, col, sku.Sum(i=>i.Quantity));
  }
}

这成功地解决了“每次循环查询”问题,但有明显的缺点……而且感觉不对。

那么,我错过了什么?让我执行类似操作的 secret EF 功能在哪里:

texasCustomers.LoadAll(c=> c.Inventories);

一次“填充”所有集合成员的导航属性?还是我从错误的角度处理了问题?

有没有一种方法可以构造查询以使 EF 生成不会变成单个巨型非规范化表的 SQL?

最佳答案

没有 secret 的 EF 功能可以让您完全按照自己的意愿行事,但有一个接近于导航属性修复的东西,即使没有 Include,它也会填充物化实体的导航属性,如果相关实体已加载到上下文中。

因此您可以先按如下方式加载相关库存:

texasCustomers.SelectMany(c => c.Inventories).Load();

然后执行并迭代主查询:

foreach (var c in texasCustomers)
{
    var inventories = c.Inventories; // must be there
    // ...
}

但是为了避免在访问导航属性时延迟加载,请确保在执行上述所有操作之前禁用延迟加载,方法是在开头插入以下行:

context.Configuration.ProxyCreationEnabled = false;

我忘记提及的一个重要细节是,使用上述技术,如果没有相关实体,导航属性将保持 null 而不是像正常用法那样返回空列表,因此请确保检查包括 null 检查或访问时使用 ?? Enumerable.Empty<Inventory>()

关于c# - Entity Framework - 为集合中的成员加载特定的导航属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43214571/

相关文章:

c# - 带进度条的 Azure Blob 存储异步下载

c# - Windows Phone 8 检测屏幕解锁

javascript - Excel 文件无法在 MVC4 中使用 AJAX 下载

c# - 使用 Entity Framework,Nop Commerce 产品导入变得更慢并且随着时间的推移使用更多内存

.net - 标准 SQL 查询比 Linq 2 SQL 快得多

C# Entity Framework 填充部分属性

c# - 减少闪烁时使用 C# Listview 模糊文本

c# - EntitySet 'Department' 基于没有定义键的类型 'Admin'

entity-framework - EF CF : many-to-many relation with additional info

c# - 在单个列表中获取重复的字段名称