Как отфильтровать дочерние объекты в запросе LINQ Include? - PullRequest
2 голосов
/ 22 сентября 2010

Я работаю с ASP.NET 3.5 SP1 и у меня есть вопрос, на котором я застрял.У меня есть страница ASPX, на которой у меня есть 2 элемента управления повторителем, 1 вложенный в другой.Исходя из кода, у меня есть простой запрос LINQ To Entities, который извлекает данные, а затем я связываю эти данные с элементами управления повторителя.Страница ASPX показана ниже:

<asp:Repeater ID="rptrMain" runat="server">
    <ItemTemplate>
        <asp:Label ID="lblName" runat="server"  ></asp:Label>
        <asp:Label ID="lblDescription" runat="server"></asp:Label>                 
        <asp:Repeater Runat="server" ID="rptrSub">
            <ItemTemplate>
                <asp:Label ID="lblPartName" runat="server" ></asp:Label>
                <asp:Label ID="lblManufacturerName" runat="server" ></asp:Label>
            </ItemTemplate>
        </asp:Repeater>
     </ItemTemplate>
</asp:Repeater>

Я связываю данные с повторителями в следующем коде:

var q = from inventories in itemContext.Inventory.Include("Parts.Manufacturer")
        select inventories;

List<Inventory> inventoryList = q.ToList();
rptrMain.DataSource = inventoryList ;
rptrMain.ItemDataBound += new RepeaterItemEventHandler(rptrMain_ItemDataBound);
rptrMain.DataBind();

void rptrMain_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        Inventory inventory = e.Item.DataItem as Inventory;
        Label lblName = e.Item.FindControl("lblName") as Label;
        Label lblDescription = e.Item.FindControl("lblDescription") as Label;

        lblName.Text = inventory.Name;
        lblDescription.Text = inventory.Description;

        Repeater rptrSub = e.Item.FindControl("rptrSub") as Repeater;
        rptrSub.DataSource = inventory.Parts;
        rptrSub.ItemDataBound += new RepeaterItemEventHandler(rptrSub_ItemDataBound);
        rptrSub.DataBind();
    }
}

void rptrSub_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        Part part = e.Item.DataItem as Part;
        Label lblPartName = e.Item.FindControl("lblPartName ") as Label;
        Label lblManufacturerName = e.Item.FindControl("lblManufacturerName") as Label;

        lblPartName.Text = part.Name;
        lblManufacturerName.Text = part.Manufacturer.Name
    }
}

Инвентарь имеет отношение 1 ко многим к Части и Частиимеет отношение один к одному с производителем.

Теперь мой вопрос: как отфильтровать дочерние объекты Inventory в запросе LINQ?Например, я бы хотел получить только те части, которые имеют определенный тип PartType.Например:

where parts.Type == Tire

Я нашел этот полезный совет http://blogs.msdn.com/b/alexj/archive/2009/06/02/tip-22-how-to-make-include-really-include.aspx Хотя это все еще не позволяет мне фильтровать дочерние объекты?

1 Ответ

1 голос
/ 22 сентября 2010

Я думаю, что лучший способ - это отфильтровать источник данных, который используется для rptrMain, перед вызовом DataBind ().например, код может выглядеть примерно так:

var q = from inventories in itemContext.Inventory.Include("Parts.Manufacturer")
        where inventories.Part.Type == Tire
        select inventories;
...

отредактировано после первого комментария:

я объявил два новых класса, включая необходимые поля для форматирования запроса:

class AbstractPartsClass
{
    public string Name { get; set; }
    public string ManufacturerName { get; set; }
}
class AbstractInventoryClass
{
    public string Name { get; set; }
    public string Description { get; set; }
    public List<AbstractPartsClass> AbstractParts { get; set; }
}

Затем я изменил запрос и некоторую часть вашего кода, как показано ниже:

var q = from inventory in itemContext.Inventory.Include("Parts.Manufacturer")
        let filteredParts = from part in inventory.Parts
                            where part.Type == Tire //any filter condition
                            select new AbstractPartsClass()
                            {
                                Name = part.Name,
                                ManufacturerName = part.ManufacturerName
                            }
        select new AbstractInventoryClass()
        {
            Name = inventory.Name,
            Description = inventory.Description,
            AbstractParts = filteredParts.ToList(),
        };
List<AbstractInventoryClass> inventoryList = q.ToList();
rptrMain.DataSource = inventoryList ;
rptrMain.ItemDataBound += new RepeaterItemEventHandler(rptrMain_ItemDataBound);
rptrMain.DataBind();

void rptrMain_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        Inventory inventory = e.Item.DataItem as AbstractInventoryClass; //changed line
        Label lblName = e.Item.FindControl("lblName") as Label;
        Label lblDescription = e.Item.FindControl("lblDescription") as Label;

        lblName.Text = inventory.Name;
        lblDescription.Text = inventory.Description;

        Repeater rptrSub = e.Item.FindControl("rptrSub") as Repeater;
        rptrSub.DataSource = inventory.AbstractParts; //changed line
        rptrSub.ItemDataBound += new RepeaterItemEventHandler(rptrSub_ItemDataBound);
        rptrSub.DataBind();
    }
}
void rptrSub_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        Part part = e.Item.DataItem as AbstractPartsClass; //changed line
        Label lblPartName = e.Item.FindControl("lblPartName ") as Label;
        Label lblManufacturerName = e.Item.FindControl("lblManufacturerName") as Label;

        lblPartName.Text = part.Name;
        lblManufacturerName.Text = part.ManufacturerName
    }
}
...