繁体   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