我自己的OrderBy函数

时间:2011-11-12 19:15:48

标签: c# .net sql linq entity-framework

我正在编写一段代码,根据评级来订购照片列表。每张照片都存储在DB中,每张照片都有正面和负面投票数等信息。我想通过公式对它们进行排序,其中我计算正面投票的百分比,第一张照片是具有最高百分比的照片。

为此我使用了标准的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 个答案:

答案 0 :(得分:6)

删除对ToList的第一次调用并使用lambda表达式而不是定义比较器:

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 :(得分:1)

比较器代码中的计算是独立的(即比较仅取决于对可以在不参考您要比较的项目的情况下计算的值进行排序)。因此,您应首先计算正百分比数,然后在比较器中使用计算值。

如果可能,这当然应该在数据库中完成(即,如果您有权对数据库进行更改)。数据库适合于这种计算,您可以在不必缓存计算值的情况下即时执行,我的意思是有一个视图可以计算出百分比,而不是每次有预先计算和存储值时正面或负面投票。这样就无需下载所有要比较的照片,因为您只需按正百分比排序即可。下面是一些可以完成工作的示例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