【问题标题】:How to Sort in .NET Same as a SQL Server Collation?如何在 .NET 中排序与 SQL Server 排序规则相同?
【发布时间】:2011-06-04 23:55:42
【问题描述】:

我一直在对一些现有的存​​储过程进行一些 TDD。它们返回 XML,所以我一直在使用 LINQ to XML。

目前,我正在进行一项测试,以证明数据已正确排序。测试浏览 XML,并创建一个匿名类型的 IEnumerable,其中包含应排序的三列。由此,它通过对第一个 IEnumerable 进行排序来创建第二个:

var sortedColumns = from g in columns
                    orderby g.ColumnA ascending,
                            g.ColumnB ascending,
                            g.ColumnC ascending
                    select g;

最后,它断言已排序的列与使用 SequenceEquals 的未排序列相同。

当数据库排序规则与当前排序规则不同时,就会出现问题。特别是,.NET 在 ColumnB 中将“W-”放在“Wa”之前。

有没有办法按照与任意 SQL Server 排序规则相同的顺序进行排序?如果不是,那么我将如何按照与 SQL_Latin1_General_CP1_CI_AS 相同的顺序进行排序?

【问题讨论】:

标签: sql-server sorting linq-to-xml collation


【解决方案1】:

LINQ-to-SQL 不支持直接使用排序规则。如果要实现特殊排序,则必须在本地获取数据,将其转换为列表(或其他)并自行排序。

更多参考请看以下两个链接:

【讨论】:

  • 对不起,我想我不清楚。我没有使用 LINQ to SQL - 我在一些来自 SQL Server 的 XML 上使用 LINQ to XML。
  • 哦,那没关系。我会在这里回复,也许它可以帮助其他人。
【解决方案2】:

我已从 use-own-icomparert-with-linq-orderby 中删除了此内容。

        MyComparer comparer = new MyComparer();
        items = items.OrderByDescending(
                  x => property.GetValue(x), comparer).ToList();
        break;

您可以根据需要创建自定义比较器。 (您的结果可能需要具体类型而不是匿名类型 - 我还没有实际测试过)。

【讨论】:

  • 谢谢,但是哪个比较器?有没有一种通用的方法来创建一个匹配任何 SQL Server 排序规则的比较器,或者你能告诉我代码来比较像 SQL_Latin1_General_CP_CI_AI 吗?
  • 我不相信 SQL Server 排序规则有现成的 IComparer。您需要创建一个实现 IComparer 的类,并自己进行适当的比较。
  • (cont..) 我并不是说它会很漂亮:) 显然,如果你特别想要 SQL_Latin1_General_CP1_CI_AI,你可以执行 ToLower() (CI)。我猜是重音的搜索/替换(AI)?这比我研究的要远一些......
【解决方案3】:

如果是 Windows 排序规则,则归结为设置适当的区域设置和排序顺序,如 Sort Order Identifiers,在 .Net 世界中按照当前设置的 UI 文化进行。

如果是 SQL 排序规则,那么就有点复杂了。如果您使用 VARCHAR ,您将失去锁定。对于 NVARCHAR,有一些希望。见Comparing SQL collations to Windows collations:

SQL 排序规则的排序规则 非 Unicode 数据不兼容 提供的任何排序例程 微软视窗操作系统 系统;然而,排序 Unicode 数据与 特定版本的 Windows 排序规则。因为比较 非 Unicode 和 Unicode 数据的规则 是不同的,当你使用 SQL 你可能会看到不同的排序规则 相同的比较结果 字符,取决于 底层数据类型。例如,如果 您正在使用 SQL 排序规则 “SQL_Latin1_General_CP1_CI_AS”, 非 Unicode 字符串 'a-c' 小于 字符串 'ab' 因为连字符 ("-") 被排序为单独的 “b”之前的字符。 但是,如果您转换这些字符串 到 Unicode 并且你执行相同的操作 比较,Unicode 字符串 N'a-c' 被认为大于 N'ab' 因为 Unicode 排序规则使用 忽略连字符的“单词排序”。

出于您的目的 (TDD),我建议您远离可疑字符,例如连字符 -,或者一个接一个地使用两个 s(德国 ss 问题),或者大写 I(土耳其语 colliton 问题) ,sh(西班牙语排序问题)等等等等...坚持正确排序的一小部分字符,例如a,A,b,B。我是认真的。

【讨论】:

  • 不幸的是,我们不能使用干净的数据 - 我必须使用那里的数据。
  • 测试存储使用 SQLite 或 SQL CE 怎么样?他们有排序规则。
  • 或者,“激进的概念”,使用“单元测试数据库”进行单元测试,而不是我在集成环境中用于测试应用程序的数据库。嗯。
  • 抱歉这么久才接受您的回答。你让我走上正轨。自一月份以来,我所有与数据库相关的单元测试都在事务中插入了测试数据(可能首先截断表),然后在测试结束时回滚。我正在努力进行“datadude”数据库单元测试,首先部署一个干净的数据库副本,然后通过数据生成计划填充它。
  • 那么如何使用 .Net 比较器来模仿 Windows“SQL_Latin1_General_CP1_CI_AS”排序规则的规则?我没有找到关于这个主题的任何好信息(除了这个答案)。如果可以避免它并且仍然获得 100% 准确的结果(相对于 sql server 的实现),我不想加载 sqlparser 库来使用它的预构建比较器。
【解决方案4】:

编写一个自定义的IComparer 实现,实际调用 SQL Server 来比较它要求比较的两个值。

这会很慢,有点傻,但它会完全按照你的要求做。

或者,如果您只关心精确复制一个特定的排序规则序列而不是任何随机排序规则,那么编写一个一次性使用例程来调用 SQL Server 并按照 SQL Server 的顺序为您构建一个所有字符的集合放置它们并使用它来构建一个自定义的IComparer 实现,然后它将匹配 SQL Server 的序列,而无需在运行时调用 SQL Server。

【讨论】:

  • 感谢您的回答。我希望我可以投票两次。我会将其标记为已接受的答案,除了 Remus Rusanu 的答案实际上让我走上了正确的道路——我认为这是处理所有这些问题的正确方法——在干净的数据库中创建自己的数据,或者通过在事务中执行它并在测试结束时回滚。
猜你喜欢
  • 2010-10-24
  • 2011-05-05
  • 2023-04-11
  • 2012-06-08
  • 2010-10-07
  • 2020-12-16
  • 2012-01-21
  • 2014-08-15
  • 1970-01-01
相关资源
最近更新 更多