【问题标题】:My own OrderBy function我自己的 OrderBy 函数
【发布时间】:2011-11-12 19:15:48
【问题描述】:

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

为此,我使用了标准的 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();

【问题讨论】:

  • 在考虑问题的答案之前,在您的方法 PictureComparer.Compare() 中,当您计算 firstPictureScore 和 secondPictureScore 时,您可能会忘记 * 100。它不会改变比较中的任何内容
  • 有什么理由不能编写一个只返回所需记录并从 EF 调用它的存储过程?
  • “我想要的照片”是什么意思?前 X 个?
  • @PierrOz,是的,你是对的,我可以省略“*100”,前 X 张照片的意思是我使用“.Skip(0 * 10).Take(10 )" 功能仅从列表中的选定位置拍摄 10 张照片,这就是为什么我不想从数据库中下载所有照片并对其进行排序。
  • @Oded,也许我可以,但这不是我曾经做过的事情,这就是为什么我要求这种情况下的最佳解决方案,最有效和最容易生产的解决方案。跨度>

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


【解决方案1】:

删除对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();

【讨论】:

  • 哇,真快。它看起来像一段很棒的代码,据我所知,排序是在数据库端完成的,对吧?但是我对那个代码有一个问题,我不想排除有0个正票或反对票的元素,我只想把它们放在列表的末尾,有可能实现吗?
  • 哇,伙计,你是最棒的!非常感谢你,就像一个魅力:)
【解决方案2】:

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

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

【讨论】:

  • 很好,据我了解,最好始终存储“positivePercentage”值,并在添加新投票时计算它?
  • 这是一种方法,但可能不是必需的。只要有一个维护计算的视图。最简单的方法是创建两个视图...第一个总结正面和负面投票(根据我上面代码中的倒数第二个 select 语句),第二个视图引用此视图并计算出百分比值(根据上面的最后一个 select 语句)。这样,当有人投票时,您无需执行任何操作,因为视图始终是最新的。
猜你喜欢
  • 2016-11-29
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多