在LINQ to Entities中,您如何订购如下?

时间:2018-02-12 06:51:20

标签: c# sql entity-framework linq

我有一个可查询的具有“代码”字段的实体

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”。 此代码字段中也包含任意数量的“。”。

如果您需要更多信息,请与我们联系。

4 个答案:

答案 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。