C# 使用LINQ to实体对多级子集合进行排序

C# 使用LINQ to实体对多级子集合进行排序,c#,entity-framework,linq,sorting,C#,Entity Framework,Linq,Sorting,考虑以下模型: public class Form { public Guid Id { get; set; } public List<Section> Sections { get; set; } } public class Section { public Guid Id { get; set; }

考虑以下模型:

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;
    }
}
从那里,我可以通过使用以下方法获得实际的
表单
对象:

var form = query.ToList().Select(q => q.Root).FirstOrDefault();
我无法理解的是如何编写LINQ查询以将此行为扩展到第二级集合(每个
部分
对象中
问题
对象的集合)

*更新*


请参阅下面我对Ivan的评论,其中解释了这个问题如何不重复。

要实现您的需求,您可以使用:

扩展方法允许您将与查询相关的实体包括在其中,甚至包括深层次的实体(请查看上面我引用的备注部分)

第二种解决方案可能是使用,如果您没有禁用此功能(默认情况下为启用),则需要满足某些条件才能使用,例如,您的导航属性必须是
virtual

更新 您也可以在内存中对导航属性进行排序,如@ IvStoev引用的解决方案,但是如果您想将相关实体按顺序排序、过滤,在其他操作中,可以考虑使用:


但IMHO最好的解决方案是创建自定义类(也称为)以投影所需的结果,只加载一次往返所需的数据,以实现您可以使用的目标:

扩展方法允许您将与查询相关的实体包括在其中,甚至包括深层次的实体(请查看上面我引用的备注部分)

第二种解决方案可能是使用,如果您没有禁用此功能(默认情况下为启用),则需要满足某些条件才能使用,例如,您的导航属性必须是
virtual

更新 您也可以在内存中对导航属性进行排序,如@ IvStoev引用的解决方案,但是如果您想将相关实体按顺序排序、过滤,在其他操作中,可以考虑使用:


但最好的解决方案是创建自定义类(也称为)来投影所需的结果,在一次往返中只加载所需的数据

记住,您是在直接查询整个表集,那么您就不需要使用方法
.Include()
快速加载

下面是一个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();
//TODO:用实际上下文DbSet替换空值
IQueryable forms=null;
var form=forms.Select(x=>newform()
{
Id=x.Id,
Sections=x.Sections.OrderBy(s=>s.SortOrder)。选择(s=>newsection()
{
Id=s.Id,
SortOrder=s.SortOrder,
Questions=s.Questions.OrderBy(q=>q.SortOrder)。选择(q=>newquestion()
{
Id=q.Id,
SortOrder=q.SortOrder
})托利斯先生()
})托利斯先生()
}).FirstOrDefault();

请记住,您直接查询的是整个表集,因此不需要使用方法
.Include()
立即加载

下面是一个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();
//TODO:用实际上下文DbSet替换空值
IQueryable forms=null;
var form=forms.Select(x=>newform()
{
Id=x.Id,
Sections=x.Sections.OrderBy(s=>s.SortOrder)。选择(s=>newsection()
{
Id=s.Id,
SortOrder=s.SortOrder,
Questions=s.Questions.OrderBy(q=>q.SortOrder)。选择(q=>newquestion()
{
Id=q.Id,
SortOrder=q.SortOrder
})托利斯先生()
})托利斯先生()
}).FirstOrDefault();

根据我的经验,您实际上不需要像您提到的那样发出包含调用。我在上面发布的LINQ查询(没有包含调用)的工作原理是一样的。也就是说,正如我上面提到的,我能够获得第一级排序(对
部分
对象进行排序)。我需要在下一级进行排序(
问题
给定
部分中的对象
对象)。但是,您能否再解释一下,您需要如何在查询结果中投影问题集合?就像匿名类型中的新属性一样?使用上面列出的模型,我希望得到一个单独的
表单
对象,该对象的
部分
集合已排序。在每个
部分中
对象s集合,我希望对其
问题
集合进行排序。我最初发布的内容和您发布的内容将完成此要求的前半部分,但不会完成后半部分。@JasonRichmeier,请用新的更改检查我的查询。是的,
包含
无效。投影:1.使EF忽略它,2.本身定义加载的子实体。不过,这是实现OP所需的方法,尤其是当投影转换为
形式
对象时(应用
AEnumerable
后)。使用EF完成这些事情总是有点麻烦。根据我的经验,您实际上不需要像您提到的那样发出包含调用。我在上面发布的LINQ查询(没有包含调用)的工作原理相同。也就是说,正如我上面提到的,我能够获得第一级排序(对
部分
对象进行排序)进行排序。我需要在下一个级别进行排序(
问题
给定
部分
对象内的对象).但是,您能否再解释一下,您需要如何在查询结果中投影问题集合?就像匿名类型中的新属性一样?使用上面列出的模型,我想得到一个
表单foreach f in context.Form
{
   context.Entry(f).Collection(r => r.Sections)
          .Query().OrderBy(s=>s.SortOrder)
          .Load();
}
// 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();