C# 使用Linq对实体进行分组和多重排序

C# 使用Linq对实体进行分组和多重排序,c#,linq,linq-to-entities,ef-code-first,C#,Linq,Linq To Entities,Ef Code First,我有两个实体: public class Course { public int Id { get; set; } public string Name { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public virtual ICollection<Class> Classes { get; set; }

我有两个实体:

public class Course
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public virtual ICollection<Class> Classes { get; set; }
}

public class Class
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; } ]
    public Course Course { get; set; }
}
但是我不能在开始的时候安排好每一节课。我试过这个:

var myList = context.Classes
    .OrderBy(c => c.StartTime)
    .GroupBy(c => c.Course)
    .OrderByDescending(g => g.Key.StartDate).ToList()
即使这样:

var myList = context.Classes
    .GroupBy(c => c.Course)
    .OrderByDescending(g => g.Key.StartDate)
    .ThenBy(g => g.Select(c => c.StartTime)).ToList()
但是这些课程从来都不是按开始时间排序的

*编辑以获得更好的澄清: 这是针对一个Web服务的,我必须返回一个
列表
,我真的需要一种优雅的方法来实现这一点(即只使用Linq),而不需要手动创建列表。当然,除非这是不可能的


非常感谢您的帮助(我使用的是EF code first 4.3 btw)。

看起来您真的需要一个列表列表,其中每个嵌套列表都按照您提到的其他条件排序。由于您是按
课程进行分组的
,因此您可以按开始日期对组进行排序,因为组中的每个条目都有相同的开始日期。然后可以将分组的元素投影到按开始时间排序的列表中:

var myList = context.Classes
    .GroupBy(c => c.Course)
    .OrderByDescending(g => g.Key.StartDate)
    .Select(g => g.OrderBy(c => c.StartTime).ToList())
    .ToList();

由于EF创建直接SQL,因此不可能在同一SQL中进行包含排序的分组

我建议在一个Linq语句中使用EF进行分组,并以ToList()结尾。然后使用Linq对对象(内存中)进行排序,作为第二个Linq语句

因为对象已经分组,所以应该运行得很快

因此,类似的方法应该有效:

var myList = context.Classes
    .GroupBy(c => c.Course).ToList()
    .OrderByDescending(g => g.Key.StartDate).ToList()

如果您需要保留签名,我建议如下:

var myList = context.Classes
                    .GroupBy(cc => cc.Course)
                    .OrderByDescending(gg => gg.Key.StartDate)
                    .ToArray() // <- stops EF and starts L2O
                    .SelectMany(gg => gg.OrderBy(cc => cc.StartTime))
                    .ToLookup(cc => cc.Course, cc => cc)
                    .ToList();
var myList=context.class
.GroupBy(cc=>cc.Course)
.OrderByDescending(gg=>gg.Key.StartDate)
.ToArray()//gg.OrderBy(cc=>cc.StartTime))
.ToLookup(cc=>cc.Course,cc=>cc)
.ToList();

这将产生一种签名类型:
List
,并按
StartTime
对其进行正确排序。这取决于
ToLookup
在维护找到的订单方面的行为,可能会发生更改。

问题是我确实需要返回
列表。这是一个Web服务,我不能修改消费者。否则,我只需在客户机上执行
foreach(group.OrderBy(c=>c.StartTime)的var类,但遗憾的是我不能。这可能是您最好的选择。
ToLookup
返回一个
ILookup
,它实现了
IEnumerable
,这意味着您可以将其传递给Web服务(你可能必须投下它,但这不应该是一个问题)。我用一个黑客的变通方法解决了它,但这更优雅。
var myList = context.Classes
                    .GroupBy(cc => cc.Course)
                    .OrderByDescending(gg => gg.Key.StartDate)
                    .ToArray() // <- stops EF and starts L2O
                    .SelectMany(gg => gg.OrderBy(cc => cc.StartTime))
                    .ToLookup(cc => cc.Course, cc => cc)
                    .ToList();