【问题标题】:conditional include in linq to entities?有条件地包含在 linq 到实体中?
【发布时间】:2010-11-08 07:11:04
【问题描述】:

我觉得以下应该是可能的我只是不确定采取什么方法。

我想做的是使用 include 方法来塑造我的结果,即定义沿对象图遍历的距离。但是...我希望这种遍历是有条件的。

something like...

dealerships
    .include( d => d.parts.where(p => p.price < 100.00))
    .include( d => d.parts.suppliers.where(s => s.country == "brazil"));

我知道这不是有效的 linq,事实上,这是非常错误的,但本质上我正在寻找某种方法来构建一个表达式树,该表达式树将返回整形结果,相当于......

select *
from dealerships as d
outer join parts as p on d.dealerid = p.dealerid
    and p.price < 100.00
outer join suppliers as s on p.partid = s.partid
    and s.country = 'brazil'

强调连接条件。

我觉得这对 esql 来说是相当直接的,但我更喜欢动态构建表达式树。

一如既往,感谢任何建议或指导

【问题讨论】:

  • 您找到解决方案了吗?我也有同样的问题。
  • 还没有,但我仍然有兴趣并将继续追求......
  • 我也在寻找同样的东西

标签: linq entity-framework include conditional


【解决方案1】:

我知道这可以与一个单独的包含一起使用。切勿使用两个包含进行测试,但值得一试:

dealerships
    .Include( d => d.parts)
    .Include( d => d.parts.suppliers)
    .Where(d => d.parts.All(p => p.price < 100.00) && d.parts.suppliers.All(s => s.country == "brazil"))

【讨论】:

    【解决方案2】:

    是的,这就是我想要做的,我认为 Data Services 的下一次发布将有可能只执行 LINQ to REST 查询,这在我刚刚切换到加载逆向并包含相关实体的同时会很棒这将被加载多次,但理论上它只需要在第一个包含中加载一次,就像在这段代码中一样

    return this.Context.SearchHistories.Include("Handle")
        .Where(sh => sh.SearchTerm.Contains(searchTerm) && sh.Timestamp > minDate && sh.Timestamp < maxDate);
    

    在我尝试为任何 Handle 加载与逻辑匹配的 searchHistories 但不知道如何使用您发布的包含逻辑之前,因此我认为反向查找不是那么肮脏的解决方案

    【讨论】:

      【解决方案3】:

      这应该可以解决问题:

      using (TestEntities db = new TestEntities())
      {
          var query = from d in db.Dealership
                      select new
                      {
                          Dealer = d,
                          Parts = d.Part.Where
                          (
                              p => p.Price < 100.0 
                                   && p.Supplier.Country == "Brazil"
                          ),
                          Suppliers = d.Part.Select(p => p.Supplier)
                      };
      
          var dealers = query.ToArray().Select(o => o.Dealer);
          foreach (var dealer in dealers)
          {
              Console.WriteLine(dealer.Name);
              foreach (var part in dealer.Part)
              {
                  Console.WriteLine("  " + part.PartId + ", " + part.Price);
                  Console.WriteLine
                      (
                      "  " 
                      + part.Supplier.Name 
                      + ", " 
                      + part.Supplier.Country
                      );
              }
          }
      }
      

      此代码将为您提供经销商列表,每个经销商都包含经过过滤的零件列表。每个部分都引用了一个供应商。有趣的部分是您必须按照所示方式在选择中创建匿名类型。否则 Dealership 对象的 Part 属性将为空。

      此外,您必须在从查询中选择经销商之前执行 SQL 语句。否则,经销商的 Part 属性将再次为空。这就是我将 ToArray() 调用放在以下行中的原因:

      var dealers = query.ToArray().Select(o => o.Dealer);
      

      但我同意 Darren 的观点,这可能不是您图书馆的用户所期望的。

      【讨论】:

      • 关于这个的注释,我试过这个,它最初没有用。我最终发现我打开了延迟加载,这导致它不起作用。一旦我关闭延迟加载,这就像一个魅力。谢谢雅各布!
      • 这要求您返回匿名类型,而不是带有实际引用的原始类型。这“确实有效”,但让我想要一个解决方案来返回原始对象,并将实际集合对象过滤为我真正想要返回的对象。匿名返回类型确实有效......但确实不是真正想要的解决方案。
      • @VulgarBinary 你可以通过这种方式返回一个类型化的列表:var dealers = query.ToArray().Select(o =&gt; o.Dealer).ToList(); 它可以正常工作!
      • 我更喜欢这种方式,所以我不创建不必要的数组:query.Load(); var dealers = query.Select(o =&gt; o.Dealer).ToList();
      【解决方案4】:

      你确定这是你想要的吗?我要问的唯一原因是,一旦您在经销商的零件上添加过滤器,您的结果就不再是经销商。您正在处理在大多数情况下与 Dealerships 非常接近的特殊对象(具有相同的属性),但“Parts”属性的含义不同。它不是经销商和零件之间的关系,而是一种过滤的关系。

      或者换句话说,如果我从你的结果中拉出一个经销商并传递给我编写的方法,然后在我的方法中调用:

      var count = dealership.Parts.Count();
      

      我希望得到零件,而不是价格低于 100 美元的巴西过滤零件。

      如果不使用dealership对象来传递过滤后的数据,就变得很容易了。它变得如此简单:

          var query = from d in dealerships
                     select new { DealershipName = d.Name, 
      CheapBrazilProducts = dealership.Parts.Where(d => d.parts.Any(p => p.price < 100.00) || d.parts.suppliers.Any(s => s.country == "brazil")) };
      

      如果我只需要按照您的要求获取过滤后的集合,我可能会使用我上面提到的技术,然后使用 Automapper 之类的工具将过滤后的结果从我的匿名类复制到真实类。它不是非常优雅,但它应该可以工作。

      希望对您有所帮助!这是一个有趣的问题。

      【讨论】:

      • 谢谢达伦我同意就对象身份而言!我也担心,这正是 EF 可能不支持的原因。我在这里真正想做的是将诸如carpartsdb.com/dealerships/parts(price
      • 对不起,darren,请在进一步的答案中查看此文本,它会更具可读性!
      【解决方案5】:

      是我遗漏了什么,还是您只是在寻找 Any 关键字?

      var query = dealerships.Where(d => d.parts.Any(p => p.price < 100.00) || 
                                    d.parts.suppliers.Any(s => s.country == "brazil"));
      

      【讨论】:

      • 我不这么认为,据我了解,这将退回有符合条件的零件和供应商的经销商,而不是退回所有经销商,所有低于 100 的零件和巴西的所有供应商。我意识到这应该是一个外部连接。我认为我要做的是修剪结果树,而不是根据树下的值过滤顶级节点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多