Моя собственная функция OrderBy - PullRequest
4 голосов
/ 12 ноября 2011

Я пишу кусок кода, который собирается упорядочить список фотографий на основе их рейтинга. Каждая фотография хранится в БД, и у каждой есть такая информация, как количество положительных и отрицательных голосов. Я хочу упорядочить их по формуле, в которой я считаю процент положительных голосов, и первая фотография - это фотография с наибольшим процентом.

Для этого я использовал стандартный интерфейс IComparer и написал собственную функцию Comparer, которая сравнивает две фотографии. Проблема в том, что я делаю то, что мне нужно сначала загрузить список всех фотографий из БД. Кажется, что это лишние усилия, которых я бы хотел избежать. Поэтому мне интересно, возможно ли создать собственную функцию SQL, которая будет выполнять сравнение на стороне БД и возвращает мне только те фотографии, которые я хочу? Это эффективнее, чем сравнивать все фотографии на стороне сервера?

Код для моего собственного компаратора:

public class PictureComparer : IComparer<Picture>
{
    public int Compare(Picture p1, Picture p2)
    {
        double firstPictureScore = (((double)p1.PositiveVotes/(double)(p1.PositiveVotes+p1.NegativeVotes))*100);
        double secondPictureScore = (((double)p2.PositiveVotes / (double)(p2.PositiveVotes + p2.NegativeVotes)) * 100);
        if (firstPictureScore < secondPictureScore) return 1;
        if (firstPictureScore > secondPictureScore) return -1;
        return 0;
    }
}

И код, который использует comaprer:

 var pictures = db.Pictures.Include(q => q.Tags).Include(q => q.User).ToList();
 pictures = pictures.OrderBy(q => q, new PictureComparer()).Skip(0 * 10).Take(10).ToList();

Ответы [ 2 ]

6 голосов
/ 12 ноября 2011

Удалите первый вызов ToList и используйте лямбда-выражение вместо определения компаратора:

var result = db.Pictures
    .Include(q => q.Tags)
    .Include(q => q.User)
    .OrderByDescending(q => 
         q.PositiveVotes + q.NegativeVotes == 0
             ? -1
             : q.PositiveVotes / (double)(q.PositiveVotes + q.NegativeVotes))
    .Skip(n * 10)
    .Take(10)
    .ToList();
1 голос
/ 12 ноября 2011

Расчеты в вашем коде сравнения независимы (т. Е. Сравнение зависит только от упорядочения значения, которое можно вычислить без ссылки на элемент, с которым вы сравниваете).Поэтому сначала вы должны рассчитать свое положительное процентное число и просто использовать вычисленное значение в своем компараторе.

Это, безусловно, должно быть сделано в базе данных, если это возможно (т. Е. Если у вас есть доступ для внесения изменений в базу данных).Базы данных подходят для такого рода вычислений, и вы, вероятно, могли бы делать это на лету, не имея необходимости кэшировать вычисленные значения, и я имею в виду представление, которое вычисляет процент для вас, а не производит предварительный расчет и сохранение значения каждый раз, когда происходитположительный или отрицательный голос.Это избавит от необходимости скачивать все фотографии для сравнения, так как вы можете просто заказать на положительный процент.Ниже приведен пример SQL, который выполнит эту работу (обратите внимание, что это всего лишь пример ... вы можете сохранить голос как немного более эффективный).Таблица голосов содержит список всех голосов за конкретную фотографию и голосовавших за нее.

declare @votes table(
pictureId int,
voterId int,
vote int)

insert into @votes select 1,1,1
insert into @votes select 1,2,-1
insert into @votes select 1,3,1
insert into @votes select 1,4,1
insert into @votes select 2,1,-1
insert into @votes select 2,2,-1
insert into @votes select 2,3,1
insert into @votes select 2,4,1

declare @votesView table(
pictureId int,
positiveVotes int,
NegativeVotes int)

insert into @votesView
select pictureId, sum(case when vote > 0 then 1 else 0 end) as PositiveVotes, 
SUM(case when vote < 0 then 1 else 0 end) as NegativeVotes from @votes group by pictureId

select pictureId, convert(decimal(6,2),positiveVotes) / convert(decimal(6,2), (positiveVotes + negativeVotes)) as rating from @votesView
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...