我有这两个实体:
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; }
}
现在我需要按课程列出每个Class分组,并按(降序)Course.StartDate然后按Class.StartTime排序。 我可以通过课程分组并按课程顺序开始.StartDate:
var myList = context.Classes
.GroupBy(c => c.Course)
.OrderByDescending(g => g.Key.StartDate).ToList()
但是无法通过它的StartTime来管理每个Class。我试过这个:
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()
但是Classes永远不会被它的StartTime命令。
*编辑以获得更好的说明:
这是一个WebService,我必须返回一个List<IGrouping<Course, Class>>
,我真的想要一个优雅的方法(即只使用Linq),而无需手动创建列表。除非当然不可能。
任何帮助都是apreciated(我使用EF代码优先4.3 btw)。
答案 0 :(得分:2)
您似乎确实需要列表,其中每个嵌套列表都按照您提到的其他条件进行排序。由于您按Course
进行分组,因此您可以按开始日期对组进行分组,因为组内的每个条目都具有相同的开始日期。然后,您可以将分组元素投影到按开始时间排序的列表:
var myList = context.Classes
.GroupBy(c => c.Course)
.OrderByDescending(g => g.Key.StartDate)
.Select(g => g.OrderBy(c => c.StartTime).ToList())
.ToList();
答案 1 :(得分:2)
如果您需要保留签名,我建议如下:
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();
这会产生一种签名:List<IGrouping<Course, Class>>
并按StartTime
正确排序。这取决于ToLookup
在维护订单方面的行为,可能会有所变化。
答案 2 :(得分:1)
由于EF创建直接SQL,因此无法在同一SQL中执行包含排序的分组。
我建议使用EF在一个Linq语句中进行分组,然后以ToList()结束。而不是使用Linq To Objects(在内存中)作为第二个Linq语句进行排序。
哪个应该快速运行,因为对象已经分组。
所以这样的事情应该有效:
var myList = context.Classes
.GroupBy(c => c.Course).ToList()
.OrderByDescending(g => g.Key.StartDate).ToList()