2012-04-09 38 views
6

Tôi có này hai thực thể:Phân nhóm và nhiều orderings sử dụng LINQ to Entities

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; } 
} 

Bây giờ tôi cần phải liệt kê từng nhóm Class bằng cách Course và ra lệnh bằng (giảm dần) Course.StartDate sau đó bởi Class.StartTime. tôi có thể nhận được vào nhóm của khóa học và trật tự bởi Course.StartDate:

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

Nhưng không thể quản lý để còn ra lệnh cho mỗi lớp bởi nó StartTime. Tôi cố gắng này:

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

Và ngay cả điều này:

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

Nhưng Lớp học không bao giờ được ra lệnh bởi nó StartTime.

* Chỉnh sửa để làm rõ hơn: Điều này dành cho WebService và tôi phải trả lại List<IGrouping<Course, Class>> và tôi thực sự muốn một cách thanh lịch để thực hiện việc này (tức là chỉ sử dụng LINQ) mà không cần tạo danh sách theo cách thủ công. Trừ khi nó không thể tất nhiên.

Bất kỳ trợ giúp nào đều được đề xuất (tôi đang sử dụng mã đầu tiên là 4,3 btw của EF).

Trả lời

2

Nếu bạn cần phải giữ gìn chữ ký, tôi đề nghị như sau:

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(); 

Điều này dẫn đến một loại chữ ký: List<IGrouping<Course, Class>> và có họ được sắp xếp đúng theo StartTime. Điều này phụ thuộc vào hành vi của ToLookup đối với việc duy trì thứ tự tìm thấy và có thể thay đổi.

+0

Đây có lẽ là đặt cược tốt nhất của bạn 'ToLookup' trả về một' ILookup ', thực hiện' IEnumerable > ', có nghĩa là bạn có thể chuyển nó tới webservice (bạn có thể phải truyền nó, nhưng đó không phải là vấn đề). – SPFiredrake

+0

Tôi đã giải quyết nó với một cách giải quyết hackish, nhưng điều này là thanh lịch hơn nhiều. –

2

Có vẻ như bạn thực sự cần danh sách các danh sách, trong đó mỗi danh sách lồng nhau được sắp xếp theo tiêu chí bổ sung mà bạn đã đề cập. Vì bạn đang nhóm theo Course, bạn có thể đặt hàng nhóm trước ngày bắt đầu vì mỗi mục nhập trong một nhóm sẽ có cùng ngày bắt đầu. Sau đó, bạn có thể trình chiếu các yếu tố nhóm vào một danh sách lệnh của thời gian bắt đầu:

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

Vấn đề là tôi thực sự cần trả về một danh sách 'Danh sách >'. Đó là một WebService và tôi không thể sửa đổi người tiêu dùng. Nếu không, tôi sẽ chỉ đơn giản là làm một 'foreach (var lớp trong group.OrderBy (c => c.StartTime)' trên máy khách, nhưng tôi thật không may là có thể –

1

Kể từ EF tạo SQL trực tiếp nó không thể làm một nhóm bao gồm một trật tự trong SQL tương tự.

Tôi sẽ đề xuất thực hiện nhóm trong một Tuyên bố LINQ bằng EF và kết thúc bằng ToList(). Và hơn là phân loại với LINQ To Objects (trong bộ nhớ) như là một Tuyên bố LINQ thứ hai.

Điều gì sẽ chạy nhanh, vì các đối tượng đã được nhóm.

Vì vậy, một cái gì đó như thế nên làm việc:

var myList = context.Classes 
    .GroupBy(c => c.Course).ToList() 
    .OrderByDescending(g => g.Key.StartDate).ToList() 
Các vấn đề liên quan