2013-11-14 3 views
2

У меня есть коллекция объектов, содержащих транзакционные данные. Этот набор данных имеет 3-х уровневые отношения между родителями и дочерними элементами с уровнями: Project> Stage> Transaction. Для каждого проекта и этапа будет проведено несколько транзакций.Как построить оператор наличия в linq с максимальным значением?

class CostElement 
{ 
    string ProjectNumber { get; set; } 
    string Stage { get; set; } 
    string DerivedCostElement { get; set; } 
    DateTime? Date { get; set; } 
    decimal? Amount { get; set; } 
} 

То, что я хочу, чтобы найти уникальный перечень элементов затрат (DerivedCostElement), со счетчиком максимального количества раз он используется в любой одном проекте. То есть Подсчитайте количество этапов для каждого проекта, а затем выберите максимальное значение.

То, что я пытался до сих пор:

//count all cost elements per project 
var aggregateQuery = from ce in _costElements 
        group ce by new { ce.ProjectNumber, ce.Stage, ce.DerivedCostElement } 
        into g 
        select new 
        { 
         g.Key.DerivedCostElement, 
         g.Key.ProjectNumber, 
         g.Key.Stage 
        }; 

//select cost elements having max count 
var countQuery = from g in aggregateQuery 
       group g by new { g.DerivedCostElement, g.ProjectNumber } 
       into grp 
       select new CostElementCount 
       { 
        CostElement = grp.Key.DerivedCostElement, 
        ProjectNumber = grp.Key.ProjectNumber, 
        Count = grp.Count() 
       }; 

return countQuery.ToList(); 

Это по большей части работ, я в конечном итоге со списком элементов затрат на проект и максимальное количество вхождений в проекте. Однако результаты по-прежнему за проект, я хочу, это уникальный список только с максимум.

Может ли кто-нибудь помочь мне получить правильный результат? Также будут приветствованы любые предложения о том, как писать это более эффективно или лаконично.

ответ

4

Я не уверен в написании первых двух запросов, которые у вас более эффективны, но я думаю, что добавить следующую строку до того, как ваш оператор возврата получит желаемые результаты.

countQuery = countQuery.OrderByDescending(x => x.Count).GroupBy(x => x.CostElement).Select(g => g.First()); 

Или держать синтаксис более последовательной

countQuery = from cq in countQuery 
      orderby cq.Count descending 
      group cq by cq.CostElement 
       into grp 
      select grp.First(); 

Вот данные тестирования я использовал ...

_costElements = new List<CostElement>(); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "a", DerivedCostElement = "ce6" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "b", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "x", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "b", DerivedCostElement = "ce2" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "b", DerivedCostElement = "ce3" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "c", DerivedCostElement = "ce3" }); 
_costElements.Add(new CostElement() { ProjectNumber = "a", Stage = "d", DerivedCostElement = "ce3" }); 
_costElements.Add(new CostElement() { ProjectNumber = "b", Stage = "e", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "b", Stage = "f", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "c", Stage = "g", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "c", Stage = "h", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "c", Stage = "h", DerivedCostElement = "ce2" }); 
_costElements.Add(new CostElement() { ProjectNumber = "c", Stage = "i", DerivedCostElement = "ce2" }); 
_costElements.Add(new CostElement() { ProjectNumber = "d", Stage = "j", DerivedCostElement = "ce2" }); 
_costElements.Add(new CostElement() { ProjectNumber = "d", Stage = "k", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "d", Stage = "l", DerivedCostElement = "ce1" }); 
_costElements.Add(new CostElement() { ProjectNumber = "d", Stage = "m", DerivedCostElement = "ce1" }); 

И результаты, которые я придумал (с небольшим количеством переупорядочение результатов countQuery) были ...

CostElement: ce1 ProjectNumber: d Количество: 3

CostElement: CE2 ProjectNumber: C Кол-во: 2

CostElement: ce3 ProjectNumber: граф: 3

CostElement: CE6 ProjectNumber: граф: 1

который я думаю, это список всех а также проект и счет, где каждый из них больше всего выглядит. Этот вывод получен из ToString(), который я добавил в CostElementCount

public string ToString() 
{ 
    return string.Format("CostElement: {0} ProjectNumber: {1} Count: {2}", CostElement, ProjectNumber, Count); 
} 
+0

Спасибо за ваш ответ. Это то, чего я хочу, но, возможно, я не совсем понял в своем вопросе. Это возвращает элемент затрат с наибольшим использованием. То, что я хочу, это список всех элементов затрат, причем максимальный каждый используется в проекте. – codemonkeh

+0

Однако, если я просто перегруппирую свой запрос снова с помощью элемента затрат (например, в вашем вопросе), я могу просто сделать max там, и он работает. Хотя я не могу не надеяться, что есть более короткий способ сделать это. – codemonkeh

+0

В моем тестовом решении я придумал список всех элементов затрат, а также название проекта, в котором было найдено самое большее, и счет. Возможно, я смоделировал это неправильно. Я добавил дополнительную информацию к моему ответу. –