我有一个可查询的具有“代码”字段的实体
1.1.1,
1.1.2,
1.1.3,
1.1.4,
...,
1.1.10,
1.1.11
不幸的是,当我对查询执行.OrderBy(x=> x.Code)
时,它会按以下顺序返回
1.1.1,
1.1.10,
1.1.11,
1.1.2,
1.1.3,
...
如何使对象列表按代码字段排序,用“。”分隔,并作为每个部分之间的整数?
这是客户数据,所以我不能只在1号码前加上“0”。 此代码字段中也包含任意数量的“。”。
如果您需要更多信息,请与我们联系。
答案 0 :(得分:5)
Version类应该是一个很好的方法。不幸的是Version.Parse
在Linq2Entity失败了,所以你必须先从你的sql-server获取数据并在之后对其进行排序。
var result = input.AsEnumerable<string>().OrderBy(x => Version.Parse(x.Code));
答案 1 :(得分:5)
如果您可以做出一些假设,就像每个节点都可以有最多n个字母。你可以使用这段代码。
.OrderBy(x => String.Concat( x.Code.Split('.')
.Select(ss => ss.PadLeft(3, '0'))) )
答案 2 :(得分:1)
如果您的表中有非常重要的数据 - 您无法真正使用提议的解决方案,这些解决方案需要从服务器提取所有数据然后在客户端上进行排序。要在服务器上执行此操作并仍然使用实体框架,您需要创建SQL函数或可计算列并按此排序,除非您可以使用仅由Entity Framework可转换为SQL的函数找出如何将代码转换为可排序的形式。如果您使用的是SQL Server,则SQL函数的示例如下:
CREATE FUNCTION dbo.DotSeparatedSort(@input varchar(max))
RETURNS hierarchyid
AS
BEGIN
return CAST(N'/' + replace(@input, '.', '/') + N'/' AS hierarchyid)
END
将点分隔数转换为hierarchyid
类型,它具有您需要的排序语义。
使用计算列可以完成相同的操作(只需将CAST(N'/' + replace(Code, '.', '/') + N'/' AS hierarchyid)
作为公式)。
然后你需要将函数导入EF模型(详细信息取决于你使用的EF版本,如果是代码优先或数据库优先)并按此排序:
ctx.Entities.OrderBy(c => ctx.DotSeparatedSort(c.Code))
将被翻译为select * from Entities order by dbo.DotSeparatedSort(Code)
。在计算列的情况下,你显然只是按此排序。
如果您使用计算列 - 您可以在其上定义索引,因此如果您有非常大量的数据 - 我会因此而更喜欢计算列。
答案 3 :(得分:0)
在执行查询(例如LINQ to Entities)时应用正确的排序(OrderBy
)是有问题的,因为表达式直接转换为ORDER BY
SQL表达式,并且没有这样的SQL子句。
您可以执行的操作是在没有特定排序的情况下执行SQL以实现数据(例如,在其上运行.ToList()
),然后使用this specific Sort Override对内存中的数据进行排序。
这是您的自定义Comparer实现的样子(从上面复制并更新,左边的注释等):
public class CodeComparer : IComparer<MyEntity>
{
public int Compare(MyEntity x, MyEntity y)
{
if (x == null)
{
if (y == null)
{
// If x is null and y is null, they're
// equal.
return 0;
}
else
{
// If x is null and y is not null, y
// is greater.
return -1;
}
}
else
{
// If x is not null...
//
if (y == null)
// ...and y is null, x is greater.
{
return 1;
}
else
{
return ToComparableString(x.Code).CompareTo(ToComparableString(y.Code));
}
}
}
private string ToComparableString(string input)
{
var split = input.Split(new [] {'.'});
return string.Join(".", split.Select(x => x.PadLeft(5, '0')));
}
}
然后,您应用排序:
var query = (...your Query or data source...).ToList();
var sortedList = query.Sort(new CodeComparer());
它会将类似“1.15.141”的字符串转换为“00001.00015.0141”,使其具有可比性。 (您也可以删除点.
,也可以将填充长度调整为预期的最大数量,例如,如果每个“节点”最多有99个,则将其设为2而不是5。