Преобразование SQL Rank() в LINQ или альтернативное

У меня есть оператор SQL, который работает по желанию/ожиданию. Однако я хотел бы перевести его в оператор LINQ (Lambda??), чтобы он соответствовал остальной части моего DAL. Однако я не могу понять, как имитировать Rank() в LINQ.

Причина, по которой я разместил ее здесь, что, возможно, является ошибкой, заключается в том, чтобы увидеть, есть ли у кого-либо альтернатива выражению Rank(), чтобы я мог переключиться. Альтернативно, если есть способ представления Rank() в LINQ, который также будет оценен.

USE CMO

SELECT      vp.[PersonID] AS [PersonId]
            ,ce.[EnrollmentID]
            ,vp.[FirstName]
            ,vp.[LastName]
            ,ce.[EnrollmentDate]
            ,ce.[DisenrollmentDate]
            ,wh.WorkerCategory

FROM  [dbo].[vwPersonInfo] AS vp
            INNER JOIN 
            (
                  [dbo].[tblCMOEnrollment] AS ce
                  LEFT OUTER JOIN
                        (
                              SELECT   *
                                          ,RANK()OVER(PARTITION BY EnrollmentID ORDER BY CASE WHEN EndDate IS NULL THEN 1 ELSE 2 END, EndDate DESC, StartDate DESC) AS whrank 
                              FROM  [dbo].[tblWorkerHistory]
                              WHERE WorkerCategory = 2
                        ) AS wh 
                              ON ce.[EnrollmentID] = wh.[EnrollmentID] AND wh.whrank = 1
            ) 
                  ON vp.[PersonID] = ce.[ClientID]

WHERE (vp.LastName NOT IN ('Client','Orientation','Real','Training','Matrix','Second','Not'))
AND (
            (wh.[EndDate] <= GETDATE())
            OR wh.WorkerCategory IS NULL
      ) 
AND (
            (ce.[DisenrollmentDate] IS NULL) 
            OR (ce.[DisenrollmentDate] >= GetDate())
      )

Ответ 1

Вот пример, который показывает, как я смоделировал Rank() в Linq:

   var q = from s in class.student
                 orderby s.Age descending
                 select new { 
                     Name = s.name, 
                     Rank = (from o in class.student
                             where o.mark > s.mark
                             select o).Count() + 1 
                 };

Ответ 2

LINQ имеет встроенную ранговую функциональность, но не в синтаксисе запроса. При использовании синтаксиса метода большинство функций linq входят в две версии: нормальную и одну с поставленным рангом.

Простой пример, который выбирает только каждого другого ученика, а затем добавляет индекс в результирующую последовательность к результату:

var q = class.student.OrderBy(s => s.studentId).Where((s, i) => i % 2 == 0)
.Select((s,i) => new
{
  Name = s.Name,
  Rank = i
}

Ответ 3

Если вы хотите имитировать ранг, вы можете использовать следующий запрос linq.

      var q = (from s in class.student
                select new
                {
                    Name = s.Name,
                    Rank = (from o in class.student
                            where o.Mark > s.Mark && o.studentId == s.studentId
                            select o.Mark).Distinct().Count() + 1
                }).ToList();

вы можете использовать порядок, например:

      var q = (from s in class.student
                orderby s.studentId 
                select new
                {
                    Name = s.Name,
                    Rank = (from o in class.student
                            where o.Mark > s.Mark && o.studentId == s.studentId
                            select o.Mark).Distinct().Count() + 1
                }).ToList();

но порядок не имеет значения в этом запросе.

Ответ 4

На основе ответа от @Totero, но с реализацией lamda. Высший балл = более высокий ранг.

var rankedData = data.Select(s => new{
                    Ranking = data.Count(x => x.Value > s.Value)+1,
                    Name = s.Key,
                    Score = s.Value});

Для этого ввода:

{ 100, 100, 98, 97, 97, 97, 91, 50 }

Вы получите этот вывод:

  • Оценка: Ранг
  • 100: 1
  • 100: 1
  • 98: 3
  • 97: 4
  • 97: 4
  • 97: 4
  • 91: 6
  • 50: 7