【问题标题】:Creating a custom OrderByDescending() for an IQueryable<T>为 IQueryable<T> 创建自定义 OrderByDescending()
【发布时间】:2012-04-27 03:20:15
【问题描述】:

以下是一些我想从高到低排序的值示例。

8,929 viewers
18,213 viewers
2,223 viewers
41,231 viewers

这是我正在使用的查询示例:

streams = streamRepository.FindAll()
                          .OrderByDescending(s => s.ViewCount)
                          .Take(4);

这不能正常工作,因为我想它将参数作为字符串,而不是 int,但这并不奇怪。

你建议我如何使用干净的 C#/Linq 代码创建这个“排序”?

理想情况下,使用上面的数据示例,生成的有序集将是:

41,231 viewers
18,213 viewers
8,929 viewers
2,223 viewers

【问题讨论】:

  • 你在查询什么数据库?
  • @Gabe: Microsoft SQL Server 2008 R2。
  • 如果值是数字,您应该将它们作为数字存储在数据库中。
  • 你有多少行?如果你有很多,那么这将是低效的,因为数据库必须对整个表进行排序。不是很多,还不如在客户端做排序,让代码更容易写。
  • 是时候将您的数据库架构重构为更合适的架构了——这是获得长期解决方案的唯一合理方法。

标签: c# linq entity-framework-4 iqueryable


【解决方案1】:

类似的东西(更伪,没有测试任何东西但应该很接近)......

streams = streamRepository.FindAll()
                          .Select(s=> new { Original = s, Count = ParseToInt(s.ViewCount)})
                          .OrderByDescending(a => a.Count)
                          .Take(3);

...其中ParseToInt 是将该字符串简单解析为 count (只是拆分为 ' ' 并首先解析为 int 我猜)

希望对大家有所帮助

编辑:这适用于无 - Db 场景

在 Db 绑定查询的情况下 - 您需要使用一些映射的 SQL 函数将“字符串”解析为 int (并且可以从 linq 映射到 SQL) - 但我不确定现在会做什么成为做到这一点的最佳方式。此外,您还需要进行选择,以便获取所有数据。
在这种情况下,通常在 Db 中保留一些 int 字段可能是最好的(而不是字符串)

【讨论】:

    【解决方案2】:

    如果格式始终相同,我会试一试:

    streams = streamRepository.FindAll()
        .AsEnumerable()
        .OrderByDescending(s => 
            int.Parse(s.ViewCount.Substring(0, s.ViewCount.IndexOf(' ') - 1))
        .Take(4);
    

    【讨论】:

    • 你确定 EF 可以将string.Split() 翻译成 SQL 吗?
    • @svick:这也是我关心的问题。
    • @JustinNiessner,我以为你可以使用 IndexOf()Substring() 来做到这一点,但我懒得实际尝试。
    • @Justin:你是说string.Substring 不能转化为T-SQL SUBSTRING 函数吗? msdn.microsoft.com/en-us/library/ms187748.aspx
    • @Gabe - 我认为它没有(即使它应该)但显然我错了。要么在 LINQ to SQL 中工作,要么在 Entity Framework 中将其删除。
    【解决方案3】:

    也许不是最巧妙的解决方案。但也许是这样的:

    streamRepository.FindAll()
            .OrderByDescending(t => t =>Convert.ToDouble(
                     t.ViewCount.Substring(0,t.ViewCount.IndexOf(' '))))
    

    生成的sql。不要那么可怕,它可以在 linqpad 中使用:

    -- Region Parameters
    DECLARE @p0 Int = 0
    DECLARE @p1 NChar(1) = ' '
    -- EndRegion
    SELECT [t0].[SomeText]
    FROM [Table1] AS [t0]
    ORDER BY CONVERT(Float,SUBSTRING([t0].[SomeText], @p0 + 1, 
        (CASE 
            WHEN (DATALENGTH(@p1) / 2) = 0 THEN 0
            ELSE CHARINDEX(@p1, [t0].[SomeText]) - 1
         END))) DESC
    

    因为 linq 可以将 substringindexof 转换为 sql 函数。但这也确实特定于格式。就像在对您问题的评论中一样,我还建议您将列拆分为列。

    【讨论】:

    • 您使用的是哪个版本的实体框架?我不认为 String.Substring 在 EF 中有翻译。
    • 也许我错过了阅读这个问题。它适用于 linq to sql。不太确定EF。因为他说查询会返回一个 IQuerable 那么他不是对数据库执行它,最终结果将是一个 sql 语句吗?
    • LINQ to Entities does not recognize the method 'Double ToDouble(System.String)' method, and this method cannot be translated into a store expression.
    猜你喜欢
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-15
    • 2015-02-20
    相关资源
    最近更新 更多