簡體   English   中英

使用LINQ對實體對多個級別的子集合進行排序

[英]Sorting Multiple Levels of Child Collections with LINQ to Entities

考慮以下模型:

public class Form
{
    public Guid Id
    {
        get;

        set;
    }

    public List<Section> Sections
    {
        get;

        set;
    }
}

public class Section
{
    public Guid Id
    {
        get;

        set;
    }

    public List<Question> Questions
    {
        get;

        set;
    }

    public int SortOrder
    {
        get;

        set;
    }
}

public class Question
{
    public Guid Id
    {
        get;

        set;
    }

    public int SortOrder
    {
        get;

        set;
    }
}

當我使用LINQ to Entities檢索一個或多個Form對象時,我希望通過SortOrder屬性對Section對象的關聯集合進行排序。 此外,在每個這些Section對象中,我想以相同的方式對相關的Question對象集合進行排序。

我不記得我在哪里讀它,但是我已經能夠使用類似於以下內容的LINQ查詢來使第一級排序工作:

var query =
    from
        f in context.Form
    where
        f.Id == *some form id*
    select
        new
        {
            Root = f,
            Sections = f.Sections.OrderBy(s => s.SortOrder)
        };

從那里,我可以使用類似的方法來獲取實際的Form對象:

var form = query.ToList().Select(q => q.Root).FirstOrDefault();

我無法弄清楚的是如何編寫LINQ查詢以將此行為擴展到第二級集合(每個Section對象中的Question對象的集合)。

*更新*

請參閱下面我對Ivan的評論,該評論解釋了此問題不是重復的。

要實現您所需要的,可以使用Eager Loading

var query= from f in context.Form.Include(f=>f.Sections.Select(s=>s.Questions))
           where f.Id == *some form id*
           select
                  new
                     {
                        Root = f,
                        Sections = f.Sections
                                    .OrderBy(s => s.SortOrder)
                                    .Select(s=> new{s.Id, s.SortOrder, Questions=s.Questions.OrderBy(q=>q.SortOrder)})
                     };

Include擴展方法使您甚至可以將與查詢相關的實體包括在內,甚至包括更深層次的內容(請查看我在上面引用的鏈接中的“ 備注”部分)。

第二種解決方案可能是使用延遲加載 ,如果您尚未禁用此功能(默認情況下處於啟用狀態),則需要滿足一些要使用的要求 ,例如,導航屬性必須為virtual

更新資料

您也可以像@IvanStoev引用的帖子中的解決方案一樣對內存中的導航屬性進行排序,但是,如果要將相關實體按某種順序進行過濾,過濾以及其他操作,則可以考慮使用Explicit Loading

foreach f in context.Form
{
   context.Entry(f).Collection(r => r.Sections)
          .Query().OrderBy(s=>s.SortOrder)
          .Load();
}

但是恕我直言,最好的解決方案是創建自定義類(也稱為DTO )以投影所需的結果,僅在一次往返中加載所需的數據

考慮到您直接查詢整個表集,那么就不需要使用.Include()方法來進行.Include() Eager Loading

這是通過顯式映射屬性/列來解決此問題的lambda表示方式。

// TODO: replace the null value with a real context DbSet<Form>
        IQueryable<Form> forms = null;

        var form = forms.Select(x => new Form()
        {
            Id = x.Id,
            Sections = x.Sections.OrderBy(s => s.SortOrder).Select(s => new Section()
            {
                Id = s.Id,
                SortOrder = s.SortOrder,
                Questions = s.Questions.OrderBy(q => q.SortOrder).Select(q => new Question()
                {
                    Id = q.Id,
                    SortOrder = q.SortOrder
                }).ToList()
            }).ToList()
        }).FirstOrDefault();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM