C# Linq表达式来过滤实体集合列表,并维护实体列表

C# Linq表达式来过滤实体集合列表,并维护实体列表,c#,asp.net-mvc,linq,entity-framework,C#,Asp.net Mvc,Linq,Entity Framework,假设我们有: public class Foo { public long Id { get; set; } public string Name { get; set; } public ICollection<Bar> { get; set; } } public class Bar { public long Id { get; set; } public int Age { get; set; } public virtua

假设我们有:

public class Foo
{
    public long Id { get; set; }
    public string Name { get; set; }
    public ICollection<Bar> { get; set; }
}

public class Bar
{
    public long Id { get; set; }
    public int Age { get; set; }

    public virtual Foo { get; set; }
    public long FooId  { get; set; }
}
现在,假设我想要所有这些食物,但他们的酒吧只包括年龄在5-25岁之间的酒吧

对于类似的东西,我会反向工作,获取所有的条,然后将所有相关的Foo都映射到这些条,然后将这些条重新映射回Foo。看起来比应该的要复杂得多

更清楚地说,所有的Foo只有其酒吧年龄在5到25岁之间:

如果要选择所有Foo,并且只有其酒吧年龄在5到25岁之间:

var results = 
    from f in db.Foos
    select new
    {
        f.Id,
        f.Name,
        Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25)
    };
这将产生一个匿名类型。如果需要创建命名类型,例如,如果需要将函数的结果作为列表返回,则可能应该为此结果集创建一个简单的命名类型:

public class FooWithFilteredBarResult // replace with whatever name you like
{
    public long Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<Bar> { get; set; }
}


List<FooWithFilteredBarResult> results = 
    (from f in db.Foos
     select new FooWithFilteredBarResult 
     {
         Id = f.Id,
         Name = f.Name,
         Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25)
     })
    .ToList();

这也将只选择唯一的Foo

bars.Where(b => b.Age >= 5 && b.Age <= 25).GroupBy(b => b.FooId).Select(g => g.FirstOrDefault().Foo).ToList();

您的问题有点不清楚,您是希望所有的Foo都只包含年龄在5到25之间的条,还是只包含年龄在5到25之间的条的Foo?一种尚未建议的方法是在Foo上实现一个扩展方法,声明类似于:getbarsbetween-down,int-upper;只需使用此扩展方法即可在Foo中过滤和检索正确的条。然后,您可以简单地选择所有Foo,其中Foo.getbars介于5、25.Any之间。这不需要对当前对象进行任何额外的内存分配或重构。两个缺点是,您不能简单地使用现有代码来处理过滤条,而且计算时间稍高。不幸的是,我没有计算时间。这只是对更复杂问题的简单探讨。我有数以百万计的foo和数以百万计的条,并且在没有索引的列上进行查找。Yikes.let在linq to objects中的表现相当不错,请注意。你的答案的第二个答案就是我要找的。有没有办法绕过必须指定Foo的所有属性,而只是自动选择它们并将条件放在条上?@Josh没有,不幸的是没有,尽管您可以在以后尝试过滤它们,例如在评估结果时。此外,您只需要指定所需的Foo属性。如果还有50个你不关心的属性,你可以把它们排除在外。嗯,所以我会同意这一点,但似乎无法实现,因为第二个答案使用了匿名类型。因此,不是一个列表,而是它的列表。如果我将其更改为new Foo,它会抱怨不能在LINQ to Entities查询中构造它。我得到了GroupBy。为什么选择Select/FirstOrDefault?只选择不同的Foo,否则可能会根据问题和结构重复。这似乎会返回条?这与@pswg option2答案基本相同,但它不允许我创建新的Foo?它说不能在LINQ to Entities查询中构造实体或复杂类型。@Josh看起来我们是同时提交的。嗯…我不知道你说的是通过EF过滤记录。让我想想。
public class FooWithFilteredBarResult // replace with whatever name you like
{
    public long Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<Bar> { get; set; }
}


List<FooWithFilteredBarResult> results = 
    (from f in db.Foos
     select new FooWithFilteredBarResult 
     {
         Id = f.Id,
         Name = f.Name,
         Bars = f.Bars.Where(b => b.Age >= 5 && b.Age <= 25)
     })
    .ToList();
bars.Where(b => b.Age >= 5 && b.Age <= 25).GroupBy(b => b.FooId).Select(g => g.FirstOrDefault().Foo).ToList();