2010-02-28 5 views
6

Hãy xem xét các đối tượng sau đây đơn giản và các mối quan hệ:Cách nhóm nhiều mục bằng GroupBy()?

public class Job{ 
    int JobId; 
    String name; 
    String status; 
    Discipline disc; 
    WorkCategory workCat; 
} 

public class Discipline { 
    int DisciplineId; 
    String DisciplineName; 
} 

public class Workcategory{ 
    int WorkCategoryId; 
    String WorkCategoryName; 
} 

public Class Grouping{ 
    Discipline parent; 
    List<Workcategory> children; 
} 

Các mô hình trên một mối quan hệ mà một Job được liên kết với một Discipline và một WorkCategory. Workcategory luôn là con của một phụ huynh cụ thể Discipline (mối quan hệ một-nhiều). Chúng ta có thể giả định rằng mối quan hệ của Kỷ luật được giao và Danh mục công việc sẽ luôn hợp lệ.

Vấn đề tôi đang đối mặt là khi tôi đang cố gắng tạo đối tượng kết quả Grouping dựa trên các bộ lọc được áp dụng cho Jobs. Tôi không chắc chắn Nếu điều này có thể được thực hiện hoặc nếu cách tiếp cận tôi đang dùng thậm chí là chính xác. Câu hỏi chính xác chính nó là không rõ ràng với tôi, tuy nhiên ở trên xác định các vấn đề tuyên bố.

  1. Thiết kế có thể được cải thiện không?
  2. Tôi làm cách nào để có thể nhóm Công việc theo Kỷ luật và Danh mục công việc?
  3. Tôi thậm chí có cần lớp học Grouping không?

Tôi đã thử những điều sau (đây là lần đầu tiên tôi sử dụng LINQ), nhưng không thành công vì sự hiểu biết của tôi chưa đủ. Cách khác là trước tiên hãy lấy nhóm Discipline và lặp qua nhóm ban đầu để chọn số Workcategory có liên quan.

var grouping = repository.GetJobsWithActiveStatus() 
      .GroupBy(x => new { 
            x.Discipline.DisciplineID, 
            x.Discipline.DisciplineName, 
            x.Category.WorkCategoryID, 
            x.Category.WorkCategoryName 
           }) 
      .Select(g => new Grouping{ 
           Discipline = new Discipline{ 
                DisciplineID = g.Key.DisciplineID, 
                Name = g.Key.DisciplineName 
                }, 
           Categories = ?? // this is where I am lost 
          }}); 

Edit: Sau khi đăng tải này, tôi nhận ra rằng các thông số groupby inital kết quả trong một nhóm mặt hàng trong khi tôi đang tìm kiếm kết quả Nhóm-nhóm.

Chỉnh sửa 2: Để làm rõ một chút nữa, tôi không muốn những công việc liên quan như là một phần của kết quả, nhưng nhóm chứ không phải Kỷ Luật-Workcategory - vì vậy lý do cho lớp Grouping


Initial giải pháp dựa trên @Obalix

Sửa 7-Mar-2010:

Giải pháp này không hoạt động - GroupBy trên đối tượng Kỷ luật sẽ mang lại một nhóm duy nhất cho mỗi đối tượng. Tôi nghĩ điều này là do nó là một kiểu tham chiếu. Tôi có đúng không? Tôi bước đầu chấp nhận điều này như là câu trả lời, tuy nhiên sau khi một số đầu gãi nhận ra rằng bản thân dữ liệu giả của tôi đã bị lỗi. Các câu hỏi ban đầu vẫn được trả lời.

var result = repository.GetJobsWithActiveStatus() 
     .GroupBy(x => x.disc) 
     .Select(g => new Grouping 
       { 
        Discipline = g.Key, 
        Catergories = g.GroupBy(x=>x.workCat) // <--- The Problem is here, grouping on a reference type 
           .Select(l=>l.Key) // needed to select the Key's only 
           .ToList() 
       }); 

Trả lời

2

Here is a description cách bạn có thể triển khai cơ chế nhóm phân cấp.

Một cách chung chung để làm điều này bằng cách dùng LINQ (như thể hiện trong liên kết) là:

var list = new List<Job>(); 

var groupedList = list.GroupBy(x => x.disc) 
    .Select(g => new { 
     Key = g.Key, 
     Count = g.Count(), 
     WorkCategoryGroups = g.GroupBy(x => x.workCat) 
    }); 

Tuy nhiên, liên kết cũng mô tả một cách khác mà cho phép bạn làm như sau:

var groupedList = list.GroupByMany(x => x.disc, x => x.workCat); 

Edit: Sau comment Ahmad đây là phiên bản mạnh mẽ gõ:

var groupedList = list.GroupBy(x => x.disc) 
    .Select(g => new Grouping { 
     parent = g.Key, 
     children = g.GroupBy(x => x.workCat).ToList() 
    }); 
+0

Tôi đã xem xét liên kết và đọc nhận xét đã dẫn tôi đến bài đăng khác, vì vậy sẽ xem xét thêm. Tuy nhiên, tôi đang tìm kiếm một kết quả được đánh máy mạnh mẽ (Grouping) – Ahmad

+0

Sau đó, bạn chỉ cần thay thế 'new {}' bằng 'new StrongType {}'. Và istedad của jusing 'Key',' Count', và 'WorkCategoryGroups' sử dụng các thành viên tùy chỉnh của bạn. Cách tiếp cận mở rộng được mô tả bởi liên kết được đánh máy mạnh mẽ. – AxelEckenberger

+0

FYI - đăng trong câu trả lời ở trên là rất tốt - có một bài viết tiếp theo về Dynamic GroupByMany cũng như nếu có ai quan tâm http://blogs.msdn.com/mitsu/archive/2008/02/07/linq -groupbymany-dynamically.aspx – Ahmad

2

Tôi muốn sử dụng LINQ cú pháp:

var jobsByDiscipline = 
    from j in repository.GetJobsWithActiveStatus() 
    group j by j.Discipline.DisciplineID into g 
    select new { 
     DisciplineID = g.Key, 
     Jobs = g.ToList() 
    }; 

var jobsByCategory = 
    from j in repository.GetJobsWithActiveStatus() 
    group j by j.Workcategory.WorkcategoryID into g 
    select new { 
     WorkcategoryID = g.Key, 
     Jobs = g.ToList() 
    }; 

Tôi thấy rằng dễ đọc hơn rất nhiều phương pháp xích với các tham số lambda chức năng.

Bạn có thể nhận được các nhóm bạn từ này:

var disciplineAndCategory = 
    from j in repository.GetJobsWithActiveStatus() 
    group j by j.Discipline.DisciplineID into g 
    let categories = 
     from j2 in g 
     select j2.Workcategory.WorkcategoryID 
    select new { 
     DisciplineID = g.Key, 
     Jobs = categories.Distinct() // each category id once 
    }; 
+1

+1 Đồng ý, cú pháp này ** ** dễ đọc hơn khi thực hiện nhóm. –

+0

@keith, cảm ơn vì đề xuất, nỗ lực đầu tiên của tôi sử dụng nó dường như hoạt động - tuy nhiên nó không được thử nghiệm, tuy nhiên tôi thích phương pháp tiếp cận phương pháp xích - sở thích cá nhân tôi đoán :) – Ahmad

0

Dưới đây là một cách khác mà không đòi hỏi lớp Nhóm.

ILookup<Discipline, Workcategory> result = repository 
    .GetJobsWithActiveStatus() 
    .Select(job => new {disc = job.disc, workCat = job.workCat}) 
    .Distinct() 
    .ToLookup(x => x.disc, x => x.workCat); 
+0

Sau khi thử nghiệm, nó mang lại kết quả tương tự cho Obalix câu trả lời. Nhóm cho từng môn học và danh mục công việc – Ahmad

0

Đây là giải pháp phù hợp với tôi.

Lần đầu tiên tôi cần để có được tất cả các nhóm kỷ luật, sau đó tạo danh sách danh mục công việc liên quan trong đó disciplineID bằng nhau.

var result = liveJobs 
.GroupBy(x => new { 
       x.disc.DisciplineID, 
       x.disc.DisciplineName 
        }) 
.Select(g => new Grouping() 
       { 
       parent = new Discipline(g.Key.DisciplineID,g.Key.DisciplineName), 
       children = g.Where(job=>job.disc.DisciplineID == g.Key.DisciplineID) // filter the current job discipline to where the group key disciplines are equal 
       .Select(j=>j.workCat) 
       .ToList() 
       });