2010-03-09 73 views
35

我写我公司的应用程序,我目前工作的搜索功能。当用户搜索一个项目时,我想显示最高版本(存储在数据库中)。排序依据()不是订购号正确的C#

的问题是,该版本被存储为字符串而不是int和当我对结果排序依据(Q => q.Version),它们像

1 
10 
11 
2 
3 
... 

显然2返回来到10之前。

有没有一种方法可以将版本作为一个整数进行投射或者是否存在简单的IComparer?到目前为止我找不到任何实质性的东西。

我试着这样做:

var items = (from r in results 
      select r).OrderBy(q => Int32.Parse(q.Version)); 

这将编译但不工作。

+2

我会建议你做你的问题(为了通过'Q => INT到底什么.Parse(q.Version)'); “不起作用”是什么意思? – 2010-03-09 15:26:40

+0

也许你的问题在这里:'(q => Int32.Parse(q.Version))''。它应该是'(q => Int32.Parse(q))'与下面的工作版本保持一致吗? – MusiGenesis 2010-03-09 15:27:12

+1

我收到此错误消息:查看枚举的结果时,“Method'Int32 Parse(System.String)'不支持转换为SQL” – Darcy 2010-03-09 15:27:29

回答

7

你的问题是在其他地方,以下工作:

new[] { "1", "10", "2", "3", "11" } 
    .OrderBy(i => int.Parse(i)) 
    .ToList() 
    .ForEach(Console.WriteLine); 

如果你的问题是LINQ to SQL的,然后发生了什么是CLR试图创建SQL你的LINQ的,不了解int.Parse 。你可以做的是首先从SQL获取数据,然后在所有数据加载完成后订购:

var items = (from r in results 
      select r) 
      .ToList() 
      .OrderBy(q => Int32.Parse(q.Version)); 

应该这样做。

+0

我收到此错误消息: 查看枚举结果时,“Method'Int32 Parse(System.String)'没有支持的SQL转换”。 – Darcy 2010-03-09 15:27:00

+0

Casting to List(ToList)也适用。谢谢yuriy。 – Darcy 2010-03-09 17:42:14

+0

@CodeBlend这条语句是针对Linq的对象。 – 2013-07-05 12:27:45

5

你为什么在拉姆达排序?你为什么不直接在查询中排序?

var query = from r in items 
      orderby int.Parse(r) 
      select r; 

现在我们知道你正在使用LINQ to SQL中,你可能会考虑做一些喜欢做在这一个标准的SQL调用:

Select ..., Cast(TextWhichShouldBeIntCol As int) As IntCol 
From ... 

甚至

Select ..., Cast(TextWhichShouldBeIntCol As int) As IntCol 
From ... 
Order By Cast(TextWhichShouldBeIntCol As int) 

这将作为一个int流入您的LINQ(并且如果您使用第二次迭代,请订购)。这样可以避免在LINQ中经历两次结果集(一次用于查询,一次用于排序)。

+0

其中任何一种方式都是一样的 – Darcy 2010-03-09 15:32:02

+2

不,它在性能上有所不同 - 数据库具有良好的排序过程,有些可以并行构建结果集,因此数据库中的排序通常会更快,速度也更慢。 – Mark 2010-03-09 15:39:46

+2

不仅如此,你正在遍历列表两次:一次是查询,一次是lambda。 – Thomas 2010-03-09 15:45:56

1

我做了一个测试。我有以下代码。

string[] versions = { "1", "2", "10", "12", "22", "30" }; 
foreach (var ver in versions.OrderBy(v => v)) 
{ 
    Console.WriteLine(ver); 
} 

如所预期的结果是1,10,12,2,22,30 然后让改变versions.OrderBy(v => v))versions.OrderBy(v => int.Parse(v)))。它工作正常:1,2,10,12,22,30

我认为你的问题是你的字符串像'。'的非数字字符。你会得到什么样的例外?

1

试试这个:

var items = results.(Select(v => v).OrderBy(v => v.PadLeft(4)); 

那将在LINQ2SQL

6

工作,如果你无法改变你的表定义(这样的版本是数值型),和您的查询确实是为列出的(不使用跳过,或采取或以其他方式减少结果数量),最好的办法是在未排序的结果上调用“ToList”,然后在您的代码中应用OrderBY lambda时,而不是试图在SQL Server端执行(现在应该可以工作)。

+0

啊这个工作。为什么这不会在linq语句中工作?因为在linq它试图在服务器上的情况方? – Darcy 2010-03-09 15:41:39

+0

@Darcy:看到这里... http://www.atrevido.net/blog/2007/09/05/调用+自定义+方法+ In + LINQtoSQL.aspx – 2010-03-09 15:49:11

+4

请注意,您也可以使用'AsEnumerable'而不是'ToList',它将查询提供程序更改回linq-to-objects,但保留linq查询的延迟执行语义而不是强制执行。 – 2010-03-09 16:11:41

0

这听起来像你有一个文本值而不是数值。

如果需要排序,你可以尝试:

var items = (from r in results 
      select r); 
return items.OrderBy(v=> Int.Parse(v.Version)); 
0
var query = from r in items 
      let n = int.Parse(r) 
      orderby n 
      select n; 
0
var items = (from v in results 
        select v).ToList().OrderBy(x => int.Parse(x.Version)); 
1

你为什么要排序,如果你只需要 “的最高版本”?这听起来像你可以避免一些开销,如果你使用Max()。

此外,你真的应该改变列的类型为整数。

+0

我无法使用'Max'的原因是因为我需要每个项目的最高版本。一个项目就像“name_423_1”,其中1是版本号。可能有“name_423_2”和“differentName_234_1” – Darcy 2011-03-14 21:54:58

1
var items = (from r in results 
     select r).OrderBy(q => Convert.ToInt32(q.Version)); 

肯定跑......

5

有,做了伟大的工作,当涉及到自然排序的代码真棒一块。它的名字是AlphanumComparator

示例代码:

var ordered = Database.Cars.ToList().OrderBy(c => c.ModelString, new AlphanumComparator()); 

注意,名单必须在内存中。

如果你得到的C#版本,这样做:

AlphanumComparator : IComparer<string> 

public int Compare(string x, string y) 
+2

喜欢这个,谢谢分享! – ozz 2013-03-29 13:57:10

+0

不适用于LINQ到实体框架 – gavin 2014-01-27 22:13:58

+0

@gavin:当然,如果你打算在数据库端执行查询,它将不起作用。要进行比较的值必须在内存中使用'.ToList()',这样'AlphanumComparator'才能完成它的工作。 :) – 2014-01-28 04:13:09