Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.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#_Asp.net Mvc_Linq - Fatal编程技术网

C# 包含路径表达式必须引用导航属性

C# 包含路径表达式必须引用导航属性,c#,asp.net-mvc,linq,C#,Asp.net Mvc,Linq,关于我的问题我搜索了很多,但没有找到任何明确的解决办法。我只知道我不能将Where linq子句与Include一起使用,但如何进行此查询对我来说没有意义 var brands = await _context.Brands .Include(x => x.FoodCategories .Select(y => y.Products .Where(z => z.Sugar)

关于我的问题我搜索了很多,但没有找到任何明确的解决办法。我只知道我不能将Where linq子句与Include一起使用,但如何进行此查询对我来说没有意义

var brands = await _context.Brands
            .Include(x => x.FoodCategories
                .Select(y => y.Products
                    .Where(z => z.Sugar)
                    .Select(w => w.FileDetail)))
            .ToListAsync();
实际上,我想在产品上应用Where语句,但我希望像这里一样在层次结构中使用实体。我怎么做
我已经试过用不同的问题来回答自己,但我没有抓住要点。这是我的审判:

var brands = _context.Brands
            .Select(b => new
            {
                b,
                FoodCategories = b.FoodCategories
                    .Where(x => x.BrandId == b.BrandId)
                    .Select(c => new
                    {
                        c,
                        Products = c.Products
                            .Where(y => y.FoodCategoryId == c.FoodCategoryId &&
                                        y.Sugar)
                            .Select(p => new
                            {
                                p,
                                File = p.FileDetail
                            })
                    })
            })
            .AsEnumerable()
            .Select(z => z.b)
            .ToList();
但是它并不是退回所有的产品,而是退回纯糖产品。

为什么只退回糖产品。 但它并没有退回所有的产品,而是退回仅含糖的产品

当然是。因为你要求它只给你糖产品:

var brands = _context.Brands
            .Select(b => new
            {
                b,
                FoodCategories = b.FoodCategories
                    .Where(x => x.BrandId == b.BrandId)
                    .Select(c => new
                    {
                        c,
                        Products = c.Products
                            .Where(y => y.FoodCategoryId == c.FoodCategoryId 
                                        && y.Sugar)                           //HERE!
                            .Select(p => new
                            {
                                p,
                                File = p.FileDetail
                            })
                    })
            })
            .AsEnumerable()
            .Select(z => z.b)
            .ToList();
如果你想要所有的产品;然后不要只过滤那些
Sugar
设置为true的


这里有很多冗余代码

b.FoodCategories.Where(x => x.BrandId == b.BrandId)
b.FoodCategories
已经表达了该特定品牌的食品类别
b
。您不需要
Where

这同样适用于

c.Products.Where(y => y.FoodCategoryId == c.FoodCategoryId ... )

以下是您(第二个)代码片段的改进版本:

这应该更清楚地表明,不需要自定义
Select
逻辑。您所做的只是将相关实体加载到同名的属性中。您可以简单地依赖现有实体及其关系,没有理由再次定义相同的关系

这里需要自定义
选择
的唯一原因是:

  • 您希望限制检索的列以降低数据大小(对于大型查询很有用)
  • 您希望有选择地加载子对象,而不仅仅是所有相关的子对象。你的代码表明你想要这个,但是你说“但是它没有返回所有的产品项目”,所以我得出结论,你不想根据产品的糖含量来过滤产品

为什么您的
Include
不起作用
。 简而言之:不能在includes中使用
Where
语句

Include
语句基于实体的结构,而
Where
只过滤集合中的数据。一个与另一个无关

即使你认为这样做会很好,比如“仅当家长处于活动状态时才包括他们”,但这并不是
include
的设计初衷。
Include
归结为“对于每个[type1],也加载它们相关的[type2]”。这将对查询将实例化的每个[type1]对象执行,并将加载每个相关的[type2]

重构上述代码段的下一步:

var brands = _context.Brands
                    .Include(b => b.FoodCategories)
                    .Include(b => b.FoodCategories.Select(fc => fc.Products))
                    .Include(b => b.FoodCategories.Select(fc => fc.Products.Select(p => p.FileDetail)))
                    .ToList();
包括为实体框架提供特定说明:

  • 对于每个加载的品牌,加载其相关的食品类别
  • 对于每个装载的食品类别,装载其相关产品
  • 对于每个加载的产品,加载其相关的文件详细信息
请注意,它没有指示应该加载哪些品牌!这是一个重要的区别。
Include
语句不会以任何方式过滤数据,它们只解释将要加载的每个条目需要检索哪些附加数据。
将加载哪些条目尚未定义。默认情况下,您将获得整个数据集,但在加载数据之前,您可以使用
Where
语句应用进一步的筛选

这样想:

一家餐馆希望每位新顾客的母亲都允许为顾客提供甜点。因此,餐厅起草了一条规则:“每位顾客必须带上他们的母亲”。
这相当于
db.Customers.Include(c=>c.Mother)

这并没有说明允许哪些顾客访问餐厅。它只规定任何来餐厅的顾客必须带上他们的母亲(如果他们没有母亲,他们将带上
null

请注意,无论哪位顾客来餐厅,此规则都适用:

  • 女士之夜:
    db.Customers.Include(c=>c.Mother.Where(c=>c.IsFemale)
  • 家长之夜:
    db.Customers.Include(c=>c.Mother.Where(c=>c.Children.Any())
  • 父亲名叫Bob night的人:
    db.Customers.Include(c=>c.Mother)。其中(c=>c.father.Name==“Bob”)
注意第三个例子。即使过滤父实体,也只会加载父实体。完全可以过滤相关实体值上的项,而不实际加载实体本身(父项)


您可能会问自己“为什么选择
?”。这是一个很好的问题,因为这不是直观的

理想情况下,你会想做类似的事情

context.Brand.Include(b => b.FoodCategories.Products.FileDetails)
但由于语言的限制,这是不可能的
FoodCategories
是一个
列表
,它没有
产品
属性

但是,
FoodCategory
本身确实有一个
Products
属性。这就是使用
Select
的原因:它允许您访问列表元素类型的属性,而不是列表本身。
在内部,EF将解构您的
Select
语句(这是一个
表达式
),它将确定要加载的属性。不要太担心EF在幕后是如何工作的。它并不总是美丽的


Include/Select语法不是最漂亮的。尤其是当您深入到多个级别时,写入(和读取)变得非常麻烦

因此,我建议你颠倒你的方法(从最低的孩子开始,向上钻到父母)。
context.Brand.Include(b => b.FoodCategories.Products.FileDetails)
var brands = context.FileDetails
                    .Include(fd => fd.Product)
                    .Include(fd => fd.Product.FoodCategory)
                    .Include(fd => fd.Product.FoodCategory.Brand)
                    .Select(fd => fd.Product.FoodCategory.Brand)
context.Brands
         .Include("FoodCategories")
         .Include("FoodCategories.Products")
         .Include("FoodCategories.Products.FileDetails")