Skip to main content
 首页 » 编程设计

c#之使用 LINQ to Entities 对多个级别的子集合进行排序

2024年01月31日28Renyi-Fan

考虑以下模型:

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 对象时,我希望相关联的 Section 对象集合按 SortOrder属性。此外,在每个 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扩展方法允许您将相关实体作为查询的一部分包括在内,甚至是更深的层次(查看我上面引用的 link 中的 备注 部分)。

第二种解决方案可能是使用 Lazy Loading ,如果你没有禁用这个功能,默认情况下是启用的,你需要满足一些requirements例如,要使用,您的导航属性必须是 virtual。

更新

您还可以像 post 中的解决方案一样对内存中的导航属性进行排序这是@IvanStoev 引用的,但如果您想按某种顺序带来相关实体,过滤等操作,您可以考虑使用 Explicit Loading :

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

但是恕我直言,最好的解决方案是创建自定义类(也称为 DTOs )来投影所需的结果,以便在一次往返中仅加载您需要的数据