Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架-加载集合中成员的特定导航属性_C#_Entity Framework_Linq_Linq To Entities - Fatal编程技术网

C# 实体框架-加载集合中成员的特定导航属性

C# 实体框架-加载集合中成员的特定导航属性,c#,entity-framework,linq,linq-to-entities,C#,Entity Framework,Linq,Linq To Entities,我发现了与使用加载相关的各种问题。包括,等等,但似乎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个项目。这

我发现了与使用
加载相关的各种问题。包括
,等等,但似乎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));
  }
}
这将为每个客户生成对“库存”表的查询。这是一个快速的查询,但是当您执行相同的查询1000次时,它会变得非常慢

所以我做过这样的事情:

//get customer key
var customerids = texasCustomers.Select(c=> c.ID).ToArray();
var inventories = context.Inventories.Where(i=> customerids.Contains(i.CustomerID)).ToList();
…现在我的导出循环看起来更像这样。。。对第一个示例中的nav属性进行操作的内部循环成为针对库存对象预构建列表的内存中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));
  }
}
这成功地解决了“每个循环查询”的问题,但有明显的缺点。。。只是感觉不对

那么,我错过了什么?让我做以下事情的秘密EF功能在哪里:

texasCustomers.LoadAll(c=> c.Inventories);
要一次性“填充”集合成员的所有导航属性?还是我从错误的角度看待问题


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

实际上,我认为应该将其分开

一张桌子给客户,另一张桌子给订单,另一张桌子给订单

命令将使头部变硬,使身体变硬(类似于此)

并使两者之间的关系


之后,您应该将整个子对象加载到内存中,并对其应用First()函数

没有秘密EF功能允许您完全执行您想要的操作,但是有一种叫做导航属性修复的功能,它可以填充物化实体的导航属性,即使没有
Include
,如果相关实体已经加载到上下文中

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

texasCustomers.SelectMany(c => c.Inventories).Load();
然后执行并迭代主查询:

foreach (var c in texasCustomers)
{
    var inventories = c.Inventories; // must be there
    // ...
}
但为了避免在访问navigation属性时延迟加载,请确保在执行上述所有操作之前,通过在最开始处插入以下行来禁用延迟加载:

context.Configuration.ProxyCreationEnabled = false;

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

啊,这感觉好多了。我要试试看。谢谢。好消息!这让我有了90%的机会。似乎它的某些方面我还不了解(例如:不从
.Find()
工作,但如果我给它一个
.AsQueryable()
,它还没有被处理,它能工作吗?不确定。我现在可以解决这个问题。)但它将我的EF数据库日志从4MEGAbytes导出到7KB(4个批量查询与约1000x3个零碎查询)实际上,它只在
IQueryable
s上工作。关于
Find
,几乎没有一种加载相关的数据方法不能直接使用它,所以请忘记它-使用简单的
Where
FirstOrDefault
等。尽管对于单个实体,您可以以任何方式获得它,包括
Find
,然后使用导航集合属性。顺便说一句,我在回答中使用的技术是在从link.Oops显式加载相关实体部分时应用过滤器的一种变体,用于加载集合的操作符应该是
SelectMany
。感谢您的澄清。特别感谢您提供了它的名称(导航属性修复)。这使得谷歌搜索和查找更多的参考资料变得很容易,我已经将这些参考资料添加到书签中阅读。