【问题标题】:LINQ-to-Entities with 8-bit ASCII data具有 8 位 ASCII 数据的 LINQ-to-Entities
【发布时间】:2012-07-18 01:16:37
【问题描述】:

我在处理 LINQ-to-Entities 中的 8 位“ASCII”字符时遇到了一个有趣的问题,希望有人能给我提示。

我继承了一个 SQL Server 2000 数据库,该数据库具有一些伪加密列,它们只是将字符串与 0xFF 进行异或运算。不知道为什么,我知道这很糟糕,但我们现在就是这样。

这些列的 SQL 数据类型为 char(7)char(14)。当您使用 0xFF 进行异或运算时,您在每种情况下都会设置第 8 位,因此您最终会得到非 ASCII(无论如何按照微软的定义)字符。这里似乎显示了 UTF-8,但解码却搞砸了。

我能够按如下方式读取和解码这些字符串:

  1. 使用 LINQ 作为String 获取字段。
  2. 使用System.Text.Encoding.GetEncoding(1252).GetBytes() 获取byte[]
  3. 通过与0xFF 异或每个字节进行解码
  4. 返回解码后的字符串System.Text.Encoding.GetEncoding(1252).GetString()

这很好用。

我遇到的问题是我似乎无法使用 LINQ 将 ENCODED 字符串放回 SQL Server。

我基本上是按照相反的过程做的:

  1. 使用ASCIIEncoding.GetBytes() 获取字节。 (此处不需要 CodePage 1252,因为这是一个直字符串。)
  2. 使用0xFF 编码字节。
  3. 返回带有GetEncoding(1252).GetString()的编码字符串。

如果我查看我的字符串,这正是我所期望的。但是,如果我将其填充到我的实体中并执行 SaveChanges(),则 SQL Server 中的结果值始终为一定长度的 "?????"

我确定我在这里遗漏了一些东西,但我已经尝试了所有我能想到的但无法得到它。现在我只是退回到使用SqlCommand 并使用编码字符串作为SqlParameters 进行更新的老式方式。没问题,每次都有效。

提前感谢您的帮助。


更新:

我尝试了 JamieSee 的建议,但用他的方法我什至没有得到很好的解码。我有:

    static void Main(string[] args)
    {
        Encoding characterEncoding = Encoding.GetEncoding(28591);

        HCBPWEBEntities ent = new HCBPWEBEntities();

        var encUser =
            (from users in ent.tblEmployer
            where users.ipkEmpId == 357
            select users.sKey).First();

        Console.Out.WriteLine("Original XOR Encoded PW: {0}", encUser.ToString().Trim());

        byte[] originalBytes = (from character in characterEncoding.GetBytes(encUser.ToString().Trim())
                               select (byte)(character)).ToArray();

        Console.Write("Original Bytes:\t");
        foreach (byte b in originalBytes)
        {
            Console.Write("{0:x} ", b);
        }
        Console.WriteLine(String.Empty);

        byte[] decodedBytes = (from character in characterEncoding.GetBytes(encUser.ToString().Trim())
                               select (byte)(character ^ 0xFF)).ToArray();

        Console.Write("Decoded Bytes:\t");
        foreach (byte b in decodedBytes)
        {
            Console.Write("{0:x} ", b);
        }
        Console.WriteLine(String.Empty);

        string decoded = characterEncoding.GetString(decodedBytes);
        Console.WriteLine("Decoded PW: {0}", decoded);

        ent.Dispose();
    }

但结果是:

原始异或编码密码:z?o> 原始字节:7a 9d 6f 3e 解码字节数:85 62 90 c1 解码密码:?b?A

密码其实是“abcd”

【问题讨论】:

  • 请使用 SQL Profiler 捕获 L2S 执行的 SQL 并发布。 (这样做非常容易。)
  • 我使用的是 LINQ-to-Entities 而不是 LINQ-to-SQL,但使用 Profiler 捕获 SQL 是个好主意。我会设置它,看看它说什么。但我的猜测是,它将表明 SQL 存储的正是它被告知存储的内容。我真的认为问题在于将非 ASCII 字符从 Entity FW 映射到 SQL。
  • 您对相关数据库的排序规则是什么?你可以通过SELECT collation_name FROM sys.databases WHERE name = 'mydatabase'找到它。

标签: linq entity-framework utf-8 codepages non-ascii-characters


【解决方案1】:

不要使用代码页 1252,请使用 Encoding.GetEncoding(28591) (iso-8859-1) 或 Encoding.GetEncoding(850) (ibm850),它们都提供基于 8 位 ASCII 的字符集。

这里有一些快速而肮脏的代码,您可以尝试使用不同的编码来展示您的问题和解决方案:

public static void Main()
{
    Encoding characterEncoding = Encoding.GetEncoding(28591);

    string original = "This is some bogus data to test the problem.";
    Console.WriteLine("Original String: {0}", original);

    Console.Write("Original Bytes: ");
    foreach (byte b in characterEncoding.GetBytes(original))
    {
        Console.Write("{0:x}", b);
    }
    Console.WriteLine();

    byte[] encodedBytes = (from character in characterEncoding.GetBytes(original)
                           select (byte)(character ^ 0xFF)).ToArray();

    Console.Write("Encoded Bytes: ");
    foreach (byte b in encodedBytes)
    {
        Console.Write("{0:x}", b);
    }
    Console.WriteLine();

    string encoded = characterEncoding.GetString(encodedBytes);

    byte[] decodedBytes = (from character in characterEncoding.GetBytes(encoded)
                           select (byte)(character ^ 0xFF)).ToArray();

    Console.Write("Decoded Bytes: ");
    foreach (byte b in decodedBytes)
    {
        Console.Write("{0:x}", b);
    }
    Console.WriteLine();

    string decoded = characterEncoding.GetString(decodedBytes);

    Console.WriteLine("Decoded String: {0}", decoded);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-18
    • 2011-01-27
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多