22

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

我想做的是使用 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 来说是相当直接的,但我更喜欢动态构建表达式树。

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

4

5 回答 5

15

这应该可以解决问题:

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 的观点,这可能不是您图书馆的用户所期望的。

于 2009-07-22T09:45:16.130 回答
7

你确定这是你想要的吗?我要问的唯一原因是,一旦您在经销商的零件上添加过滤器,您的结果就不再是经销商。您正在处理在大多数情况下与 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 这样的工具将过滤结果从我的匿名类复制到真实类。它不是非常优雅,但它应该可以工作。

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

于 2009-07-21T18:14:06.973 回答
2

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

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"))
于 2015-05-08T12:42:38.240 回答
1

我错过了什么,或者你不只是在寻找Any关键字?

var query = dealerships.Where(d => d.parts.Any(p => p.price < 100.00) || 
                              d.parts.suppliers.Any(s => s.country == "brazil"));
于 2009-07-06T04:52:41.477 回答
1

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

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

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

于 2009-09-22T01:02:23.247 回答