使用LINQ-to-Entities处理8位ASCII数据

7
我在使用LINQ-to-Entities处理8位ASCII字符时遇到了有趣的问题,希望有人能给我一些提示。 我继承了一个SQL Server 2000数据库,其中有一些伪加密列,它们只是将字符串与0xFF异或。不知道为什么,我知道这很糟糕,但现在就是这样。
这些列是SQL数据类型char(7)和char(14)。当您使用0xFF进行XOR运算时,您在每种情况下都会设置第8位,因此您最终得到非ASCII(按Microsoft的定义)字符。UTF-8似乎在这里是指示符,但解码变得混乱。
我可以按以下方式读取和解码这些字符串:
1. 使用LINQ将字段作为String获取。 2. 使用System.Text.Encoding.GetEncoding(1252).GetBytes()获取一个byte []。 3. 通过对每个字节进行XOR运算来解码。 4. 使用System.Text.Encoding.GetEncoding(1252).GetString()返回解码后的字符串。
这完美地工作。
我的问题是,我似乎无法使用LINQ将编码后的字符串放回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();
    }

但是结果如下:

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

实际上密码是"abcd"


请使用SQL Profiler捕获由L2S执行的SQL并发布它。(这非常容易做到。) - usr
我正在使用LINQ-to-Entities而不是LINQ-to-SQL,但使用Profiler捕获SQL是一个好主意。 我将设置并查看它说了什么。 但我的猜测是,它将显示SQL存储了确切的内容。 我真的认为问题在于从实体框架到SQL的非ASCII字符映射。 - jwh20
你的数据库排序规则是什么?你可以使用 SELECT collation_name FROM sys.databases WHERE name = 'mydatabase' 命令来查找。 - JamieSee
1个回答

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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接