2012-07-18 13 views
7

Mam interesujący problem z obsługą 8-bitowych znaków "ASCII" w LINQ-to-Entities i mam nadzieję, że ktoś może dać mi napiwek.LINQ-to-Entities z 8-bitowymi danymi ASCII

Odziedziczyłem bazę danych SQL Server 2000, która ma kilka pseudo-zaszyfrowanych kolumn, gdzie po prostu XOR'd ciąg znaków z 0xFF. Nie wiem dlaczego i wiem, że to kiepskie, ale to jest miejsce, w którym teraz jesteśmy.

Te kolumny mają typ danych SQL char(7) i char(14). Kiedy używasz XOR przy użyciu 0xFF, otrzymujesz zestaw 8 bitów w każdym przypadku, więc kończysz na znakach spoza ASCII (i tak przez Microsoft). UTF-8 wydaje się być tutaj wskazany, ale dekodowanie zostaje pomieszane.

Jestem w stanie odczytać i rozszyfrować te ciągi następująco:

  1. Get pola przy użyciu LINQ jako String.
  2. Get byte[] korzystając System.Text.Encoding.GetEncoding(1252).GetBytes()
  3. Decode przez XORing każdy bajt z 0xFF
  4. Return zdekodowany ciąg z System.Text.Encoding.GetEncoding(1252).GetString()

Działa to doskonale.

Problem polega na tym, że nie mogę wstawić łańcucha ENCODED do SQL Server używając LINQ.

ja po prostu proces odwrotny i robie:

  1. Uzyskaj bajty za pomocą ASCIIEncoding.GetBytes(). (Nie ma potrzeby stosowania CodePage 1252 tutaj, ponieważ jest to prosty ciąg znaków).
  2. Zakoduj bajty za pomocą 0xFF.
  3. Powrócić kodowany ciąg znaków za pomocą GetEncoding(1252).GetString().

Jeśli spojrzę na mój sznur, to dokładnie to, czego bym się spodziewał. Ale jeśli wypchnę to w mojej jednostce i wykonam numer SaveChanges(), wynikowa wartość w Serwerze SQL będzie zawsze wynosić "?????" o pewnej długości.

Jestem pewien, że czegoś tu nie ma, ale próbowałem wszystkiego, co mogę wymyślić i nie mogę tego zdobyć. Na razie po prostu wróciłem do staroświeckiego sposobu używania SqlCommand i wykonałem UPDATE z kodowanymi łańcuchami jako SqlParameters. Nie ma problemu, działa za każdym razem.

Z góry dziękujemy za wszelką pomoc.


Aktualizacja:

Próbowałem sugestię JamieSee i nie jestem nawet uzyskanie dobrej dekodowanie z jego metodą. Mam:

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

Ale wynik tego są:

Original XOR kodowane PW: z?O> oryginalne Bytes: 7a 9d 6f 3e dekodowane bajtów: 85 62 90 c1 Decoded PW: B A

Hasło jest faktycznie "abcd"

+0

Proszę przechwytywania SQL wykonywanego przez L2S pomocą SQL Profiler i po to. (Bardzo łatwo to zrobić.) – usr

+0

Używam LINQ-to-Entities, a nie LINQ-SQL, ale przechwytywanie SQL za pomocą Profiler jest dobrym pomysłem. Ustawię to i zobaczę, co mówi. Ale domyślam się, że pokaże, że SQL przechowuje dokładnie to, co ma przechowywać. Naprawdę uważam, że problemem jest mapowanie znaków spoza ASCII z Entity FW na SQL. – user1536209

+0

Jaka jest twoja kolekcja dla danej bazy danych? Możesz go znaleźć za pomocą 'SELECT collation_name FROM sys.databases WHERE name = 'mydatabase''. – JamieSee

Odpowiedz

1

Nie używać strony kodowej 1252 wykorzystanie Encoding.GetEncoding(28591)? (iso-8859-1) lub Encoding.GetEncoding(850) (ibm850), z których każda zawiera 8-bitowe zestawy znaków oparte na ASCII.

Oto niektóre szybkie & brudny kod, który można spróbować z różnych kodowań, aby wykazać swój problem i rozwiązanie:

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