过滤IQueryable子列表

时间:2013-05-31 20:59:31

标签: c# linq entity-framework filtering

使用实体框架,但这可能无关紧要 如果我有一个Iqueryable,我如何过滤子列表并保持IQueryable,以便它还没有命中数据库?

如果我有10个项目且每个项目有3个子项目,我该如何过滤它以便返回所有10个项目并将其子项目过滤到id = 1的位置?

class Item上有大约20个属性,所以我不想在每个属性上使用投影,因为维护问题。

items = items.select(??);//how to do this so items are returned, and their children are filtered?

class SubItem
{ private int ID { get; set; }
}
class Item 
{
private List<SubItem> SubItems { get; set; }
}

4 个答案:

答案 0 :(得分:3)

我解释您的问题,因为您想要返回所有Items,无论如何,但您想要过滤SubItems。对于IQueryable,没有好的方法可以说“我想要返回此对象,除了我想要修改版本的X属性”。如果你愿意,你必须使用select语句选择一个新对象。

选项1:单独返回数据

var itemsAndSubItems = items
    .Select(item => new 
        {
            Item = item,
            SubItems = item.SubItems.Where(sub => sub.ID = 1)
        }
    );

或者如果你不介意急切地将这些物品装入记忆中:

IEnumerable<Item> = items
    .Select(item => new 
        {
            Item = item,
            SubItems = item.SubItems.Where(sub => sub.ID = 1)
        }
    )
    .ToList()
    .Select(row => 
        { 
            var item = row.Item;
            item.SubItems = row.SubItems;
            return item;
        }
    );

选项2:返回班级的新实例(您似乎不想这样做)

IQueryable<Item> items = items
    .Select(item => new Item 
        { 
            SubItems = item.SubItems.Where(sub => sub.ID == 1),
            OtherProp = item.OtherProp
            /*etc for the other properties on Item*/
        }
    );

选项3:向您的班级添加另一个属性。我推荐这个。请注意,当您访问SubItemsWithIdOne

时,您的查询仍将返回此处的所有子项
class Item 
{
    private List<SubItem> SubItems { get; set; }
    private List<SubItem> SubItemsWithIdOne 
    {
        get 
        {
            return this.SubItems.Where(sub => sub.ID == 1); 
        }
    }
}

选项4:在SubItem上添加引用其父Item的属性。然后返回SubItem列表。这样,您就可以同时满足SubItemsItems条件。

...如果你正在使用IEnumerable,你可以这样做:

IEnumerable items = items
    .Select(item =>
        {
            item.SubItems.Where(sub => sub.ID = 1);
            return item;
        }
    );

答案 1 :(得分:2)

如果您想将儿童过滤到每个父母只有一个孩子的地方,您需要从孩子开始,选择他们的父母,不要触及父母的子项目:

IQueryable<SubItem> childItems = context
    .SubItems.Include("Item")
    .Where(si => si.Id == 1 && si.Item.SomeAttr == someValue);
//               ^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                   |                         |
//                   |           Set a condition on the parent
//  Set a condition on the child

我假设每个子项目都有一个“指向”其父项的链接。

答案 2 :(得分:1)

items.Where(i => i.SubItems.Any(subItem => subItem.Id == 1));

答案 3 :(得分:0)

我认为你在寻找的是SelectMany。例如,你的案例是这样的:

  positiveItems = items.SelectMany(x => x.SubItem).Where(x=> x.ID == 1).Select(x=>x.Item);
  //items still IQueryable , so we can concat it with another IQueryable

  negativeItems = items.SelectMany(x=>x.SubItem).Where(x=>x.ID != 1).Select(x=>x.Item);


  //just an using option
  allItems = positiveItems.Concat(negativeItems);

只是一个建议。对于大量的参考对象集,您可以使用ValueInjecter它非常简单快速。我用了几个生产项目,节省了很多次。