高级Linq排序C#

高级Linq排序C#,c#,linq-to-sql,sorting,C#,Linq To Sql,Sorting,我有一个IQueryable,它有一个页面列表 我想做:Pages.OrderByDescending(o=>CalculateSort(o.page)) 计算排序的方法类似于下面的纯英语版本: public int calculatesort(page p) { int rating = (from r in db.rating select r). sum(); int comments = //query database for comments; float

我有一个
IQueryable
,它有一个页面列表

我想做:
Pages.OrderByDescending(o=>CalculateSort(o.page))

计算排序的方法类似于下面的纯英语版本:

public int calculatesort(page p)
{
    int rating = (from r in db.rating select r). sum();
    int comments = //query database for comments;

    float timedecayfactor = math.exp(-page.totalhoursago);

    return sortscore = (rating +comments)* timedecayfactor;
}
当我运行与上面类似的代码时,会抛出一个错误,即无法将mothode calculatesort转换为sql

如何转换上面的函数以使sql能够理解,从而可以使用它对页面进行排序

对于大数据来说,这不是一个好方法吗?除了在数据库中动态排序外,是否还有其他方法用于对结果集进行排序


我已经好几天没睡了,试图修复这个问题:(

发生错误是因为LINQ无法将自定义代码/方法转换为SQL。它只能将
表达式对象
转换为SQL

在您的情况下,排序时需要执行复杂的逻辑,因此,如果您想在DB层中执行此操作,则可以使用
存储过程执行此操作

或者将所有对象加载到主内存中,并对内存中的对象运行计算排序方法

编辑:

我没有代码,所以我只能用英语描述:

  • 具有能够临时存储所有当前用户数据的表结构
  • 在Pages表中有一个计算字段,该字段保存从所有非用户特定字段计算的值
  • 编写一个存储过程,使用这两个源(temp table和calc field)中的值实际执行排序
  • 删除临时表作为存储过程中的最后一部分
  • 您可以阅读有关存储过程和

Linq希望Calculatesort返回一个“可查询”表达式,以便生成自己的SQL

In可以将“calculatesort”方法嵌入此lambda表达式中。(为了在我的环境中编译,我将变量替换为常量)


是的,计算前面的答案:LINQ to SQL不知道如何转换CalculateSort方法。在使用自定义方法之前,应该将LINQ to SQL转换为普通LINQ to对象

尝试以调用CalculateSort的方式使用它,方法是添加一个可计算的:

Pages.AsEnumerable().OrderByDescending(o => CalculateSort(o.page));
那么您可以使用OrderByDescending扩展方法

更新:
LINQ to SQL将始终将代码中的查询转换为表达式树。这几乎与任何编程语言的AST的概念相同。这些表达式树将进一步转换为特定于SQL Server的SQL的SQL表达式,因为目前LINQ to SQL仅支持SQL Server 2005和2008。

您的代码远未达到预期效果所以我在这里猜了很多,但我希望这也能给出一个想法。 正如一些人所说,您需要为Linq-2-Sql提供一个表达式树


实际上,我还没有在数据库中尝试过这种方法,基于您的代码,有太多的未知内容,因此可能仍然有无法翻译的内容。

页面
您的数据库实体吗?我的意思是
页面.orderbydescending(o=>CalculateSort(o.page))
是linq2object还是linq2sql,您的RDBMS和linq提供程序是什么?它是linq to sql。基本上有一个名为pages的表和另外两个表comments and ratings。我想使用一种类似于facebooks Edge rank的算法对这些算法进行排序。我可以在选择页面时在新对象的注释中包含评级,但我仍然无法翻译(评级+评论)*math.exp(-page.totalhoursago)进入sql。有什么想法吗?谢谢你的回答。我无法将结果加载到内存中,因为它们是数百万个结果。是否可以将上面的代码转换为表达式s?或者我必须使用存储过程。我在使用排序过程方面没有经验,或者说,
IQueryable
的实现者只有有限的abi将传递的表达式树转换为SQL(或任何查询语言)的能力.在Q的情况下,整个函数需要是可翻译的…建议的修复方法:向数据库中添加一个计算列,并对其进行排序:这只需要在LINQ表达式中指定一个属性。我同意Richards的建议,即拥有一个计算列,并对其进行排序。我一直认为用硬盘空间交换计算列是可以的初始化时间。实际的算法更复杂,还取决于其他东西,如用户特定的ass userafinity和兴趣afinity,因此我无法将其存储在数据库中。我可以通过将非用户特定的东西存储在数据库中来减少处理。我仍然需要动态执行用户特定的排序。有什么想法吗?问题是该评级和评论尚未在页面对象中准备就绪,需要从db中检索。您将通过上下文引用访问评级和评论。是否对每个页面都执行此操作?每个页面的评论和评级将不同。这取决于:页面和评论与评级之间是否存在关系如果没有,那么你必须这样使用:db.ratings.Where(r=>r.PageId==p.PageId.).Sum()等等。我可以用同样的方法来处理两个类似于:(from r in db.rating from I in db.interests,其中r.value==I.value&&r.page=page)的数据吗?在我在问题中提供的示例中,评级只是更复杂查询的一个简单示例。如果变量不是常量,我如何动态查询数据库?用实际代码替换'99'常量;等等,其他常量。我回答了你的问题吗?这是否适用于更多com复杂的数据和大约100万页?或者还有其他方法吗?非常感谢您的支持help@Marwan:对于百万条记录,您可能希望了解哈希。您也可以在不同的线程(异步)中执行此操作,并在系统运行时启动它
    Pages.AsParallel().OrderByDescending(p =>
var comments = db.comments.Where(...);
Pages.OrderByDescending(p=>(db.rating.Sum(r=>r.rate) + comments.Count()) * Math.Exp(-p.totalhoursago))
Pages.AsEnumerable().OrderByDescending(o => CalculateSort(o.page));
                     from p in pages
                     let rating = (from r in db.rating
                                   where r.PageId == p.PageId
                                   select r.Value).Sum()
                     let comments = (from c in db.Comments
                                     where c.PageId == p.PageId
                                     select 1).Count()
                     let timedecayfactor = Math.Exp(-(p.totalhoursago))
                     orderby (rating + comments)*timedecayfactor descending
                     select p;