C# 我自己的OrderBy函数
我正在写一段代码,它将根据照片的评级对照片列表进行排序。每张照片都存储在DB中,每张照片都有正面和负面投票数等信息。我想按照我计算赞成票百分比的公式排序,第一张照片是百分比最高的那张 为此,我使用了标准的IComparer界面,并编写了自己的比较器函数,用于比较两张照片。问题是我必须首先从db下载所有照片的列表。这似乎是很多我想避免的不必要的努力。所以我想知道是否有可能创建我自己的SQL函数,在DB端进行比较,并返回我想要的照片?它比在服务器端比较所有照片更有效 我自己的比较器的代码:C# 我自己的OrderBy函数,c#,.net,sql,linq,entity-framework,C#,.net,Sql,Linq,Entity Framework,我正在写一段代码,它将根据照片的评级对照片列表进行排序。每张照片都存储在DB中,每张照片都有正面和负面投票数等信息。我想按照我计算赞成票百分比的公式排序,第一张照片是百分比最高的那张 为此,我使用了标准的IComparer界面,并编写了自己的比较器函数,用于比较两张照片。问题是我必须首先从db下载所有照片的列表。这似乎是很多我想避免的不必要的努力。所以我想知道是否有可能创建我自己的SQL函数,在DB端进行比较,并返回我想要的照片?它比在服务器端比较所有照片更有效 我自己的比较器的代码: publ
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;
}
}
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();
删除对
ToList
的第一个调用,并使用lambda表达式而不是定义比较器:
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;
}
}
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();
比较器代码中的计算是独立的(即,比较仅取决于排序值,该值可以在不参考要比较的项目的情况下进行计算)。因此,您应该首先计算正百分比,然后在比较器中使用计算出的值 如果可能,这当然应该在数据库中完成(即,如果您有权对数据库进行更改)。数据库适合于这种计算,您可能不需要缓存计算的值就可以动态地进行计算,我的意思是有一个视图可以为您计算出百分比,而不是每次有赞成票或反对票时都预先计算和存储值。这样就无需下载所有照片进行比较,因为您只需按正百分比订购即可。下面是一些将完成这项工作的示例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
declare@投票表(
图片ID int,
voterId int,
投票(整数)
插入@投票选择1,1,1
插入@投票选择1,2,-1
插入@投票选择1,3,1
插入@投票选择1,4,1
插入@投票选择2,1,-1
插入@投票选择2,2,-1
插入@投票选择2,3,1
插入@投票选择2,4,1
声明@votesView表(
图片ID int,
正片,
负片(内部)
插入@votesView
选择pictureId、sum(投票>0时为1,否则为0结束)作为正数,
按pictureId从@Voces group以否定形式求和(当投票数<0时,则为1,否则为0结束)
从@votesView中选择pictureId、convert(十进制(6,2)、positiveVotes)/convert(十进制(6,2)、(正数+负数))作为评级
在考虑问题的答案之前,在方法PictureComparer.Compare()中,当计算firstPictureScore和secondPictureScore时,您可以忘记*100。它不会改变比较中的任何内容任何原因都不能编写一个只返回想要的记录并从EF调用的存储过程?那么“我想要的照片”是什么意思?第一张X照片?@PierrOz,是的,你是对的,我可以省略“*100”,对于第一张X照片,我的意思是我使用“.Skip(0*10).Take(10)”功能只从列表中选定的位置拍摄10张照片,这就是为什么我不想从数据库下载所有照片,然后对它们进行排序。@Oded,也许我可以,但这不是我曾经做过的事情,这就是为什么我要求这样一个场景的最佳解决方案,一个最有效、最容易产生的解决方案。哇,太快了。这看起来是一段很棒的代码,据我所知,排序是在DB端完成的,对吗?但是我对代码有一个问题,我不想排除那些有0个正面或负面投票的元素,我只想让它们在列表的末尾,有可能实现吗?哇,伙计,你是最好的!,非常感谢您的支持,效果非常好:)很好,据我所知,最好始终存储“正百分比”值,并在添加新投票时进行计算?这是一种方法,但可能不是必需的。只要有一个维护计算的视图。最简单的方法是创建两个视图…第一个视图汇总正面和负面投票(根据上面代码中最后一个select语句),第二个视图引用此视图并计算出百分比值(根据上面最后一个select语句)。这样,当有人投票时,您不需要做任何事情,因为视图总是最新的。