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

问题描述 投票:4回答:4

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

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

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

c# sql entity-framework linq
4个回答
5
投票

如果你可以做出一些假设,就像每个节点都可以有最多n个字母。你可以使用这段代码。

.OrderBy(x => String.Concat( x.Code.Split('.')
                                   .Select(ss => ss.PadLeft(3, '0'))) )

5
投票

Version类应该是一个很好的方法。不幸的是Version.Parse在Linq2Entity失败,所以你必须首先从你的sql-server获取数据并在之后对其进行排序。

var result = input.AsEnumerable<string>().OrderBy(x => Version.Parse(x.Code));

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)。如果是计算列,你显然只是按此排序。

如果你使用计算列 - 你可以在它上面定义索引,所以如果你有非常大量的数据 - 我更喜欢计算列。


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。

© www.soinside.com 2019 - 2024. All rights reserved.