2011-03-14 2 views
8

XmlDictionaryWriter를 사용하여 데이터 계약 serializer를 사용하여 개체를 데이터베이스에 serialize합니다. 크기와 속도가 모두 2 배 좋고 text/xml을 사용하면 효과적입니다.미리 공유 사전이있는 .NET 이진 XML

그러나 데이터베이스에서 엄청난 수의 레코드를 처리해야하는데 추가 바이트가 DB 크기의 기가 바이트로 직접 변환됩니다. 그래서 XML 사전을 사용하여 크기를 줄이는 것이 좋습니다.

어떻게하면됩니까?

XmlDictionaryWriter.CreateBinaryWriter 정적 메서드는 IXmlDictionary 형식의 2-nd 매개 변수를 사용합니다. MSDN은 "XmlDictionary를 공유 사전으로 사용합니다"라고 말합니다.

먼저 나는 시스템 제공 구현을 사용하려고했습니다 :

XmlDictionary dict = new XmlDictionary(); 
string[] dictEntries = new string[] 
{ 
    "http://schemas.datacontract.org/2004/07/MyContracts", 
    "http://www.w3.org/2001/XMLSchema-instance", 
    "MyElementName1", 
    "MyElementName2", 
    "MyElementName3", 
}; 
foreach (string s in dictEntries) 
     dict.Add(s); 

결과는 .NET 프레임 워크는 완전히 사전을 무시하고, 여전히 해당하는을 참조하는 대신 일반 텍스트로 위의 문자열을 삽입 사전 항목.

는 그럼 난 IXmlDictionary의 내 자신의 구현을 만들었습니다

class MyDictionary : IXmlDictionary 
{ 
    Dictionary<int, string> values = new Dictionary<int, string>(); 
    Dictionary<string, int> keys = new Dictionary<string, int>(); 

    MyDictionary() 
    { 
     string[] dictEntries = new string[] 
     { 
      "http://schemas.datacontract.org/2004/07/MyContracts", 
      "http://www.w3.org/2001/XMLSchema-instance", 
      "MyElementName1", 
      "MyElementName2", 
      "MyElementName3", 
     }; 

     foreach (var s in dictEntries) 
      this.Add(s); 
    } 

    static IXmlDictionary s_instance = new MyDictionary(); 
    public static IXmlDictionary instance { get { return s_instance; } } 

    void Add(string val) 
    { 
     if (keys.ContainsKey(val)) 
      return; 
     int id = values.Count + 1; 
     values.Add(id, val); 
     keys.Add(val, id); 
    } 

    bool IXmlDictionary.TryLookup(XmlDictionaryString value, out XmlDictionaryString result) 
    { 
     if (value.Dictionary == this) 
     { 
      result = value; 
      return true; 
     } 
     return this.TryLookup(value.Value, out result); 
    } 

    bool IXmlDictionary.TryLookup(int key, out XmlDictionaryString result) 
    { 
     string res; 
     if (!values.TryGetValue(key, out res)) 
     { 
      result = null; 
      return false; 
     } 
     result = new XmlDictionaryString(this, res, key); 
     return true; 
    } 

    public bool /* IXmlDictionary. */ TryLookup(string value, out XmlDictionaryString result) 
    { 
     int key; 
     if (!keys.TryGetValue(value, out key)) 
     { 
      result = null; 
      return false; 
     } 

     result = new XmlDictionaryString(this, value, key); 
     return true; 
    } 
} 

결과입니다 - 내 TryLookup 방법은 OK라고하지만 DataContractSerializer.WriteObject 빈 문서를 생성합니다.

사전 공유 사전은 어떻게 사용합니까?

미리 감사드립니다.

P. XmlBinaryReaderSession/XmlBinaryWriterSession을 망치고 싶지 않습니다. "세션"이 없으며, 대신 한 번에 많은 스레드가 액세스하는 10GB + 데이터베이스가 있습니다. 내가 원하는 것은 정적 사전 정의 된 사전입니다.

업데이트 : 확인 "XmlDictionaryWriter.Flush"를 호출해야한다는 것을 알았습니다. 유일한 나머지 질문은 - 시스템에서 제공하는 IXmlDictionary 구현이 예상대로 작동하지 않는 이유는 무엇입니까?

답변

0

XmlDictionaryWriter의 경우 세션을 사용해야합니다.
example :

private static Stream SerializeBinaryWithDictionary(Person person,DataContractSerializer serializer) 
    { 
     var stream = new MemoryStream(); 
     var dictionary = new XmlDictionary(); 
     var session = new XmlBinaryWriterSession(); 
     var key = 0; 
     session.TryAdd(dictionary.Add("FirstName"), out key); 
     session.TryAdd(dictionary.Add("LastName"), out key); 
     session.TryAdd(dictionary.Add("Birthday"), out key); 
     session.TryAdd(dictionary.Add("Person"), out key); 
     session.TryAdd(dictionary.Add("http://www.friseton.com/Name/2010/06"),out key); 
     session.TryAdd(dictionary.Add("http://www.w3.org/2001/XMLSchema-instance"),out key); 

     var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, session); 
     serializer.WriteObject(writer, person); 
     writer.Flush(); 
     return stream; 
    } 
0

내 클래스가 DataContract 속성으로 장식되지 않았을 때 내가 사용하지 않는 IXmlDictionary의 문제를 복제하는 방법으로 할 수 있었다 유일한 방법. 다음 응용 프로그램은 데코 레이팅 및 데코 레이팅되지 않은 클래스의 크기 차이를 표시합니다.

using System; 
using System.Runtime.Serialization; 
using System.Xml; 

namespace XmlPresharedDictionary 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Serialized sizes"); 
      Console.WriteLine("-------------------------"); 
      TestSerialization<MyXmlClassUndecorated>("Undecorated: "); 
      TestSerialization<MyXmlClassDecorated>("Decorated: "); 
      Console.ReadLine(); 
     } 

     private static void TestSerialization<T>(string lineComment) where T : new() 
     { 
      XmlDictionary xmlDict = new XmlDictionary(); 
      xmlDict.Add("MyElementName1"); 

      DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 

      using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) 
      using (var writer = XmlDictionaryWriter.CreateBinaryWriter(stream, xmlDict)) 
      { 
       serializer.WriteObject(writer, new T()); 
       writer.Flush(); 
       Console.WriteLine(lineComment + stream.Length.ToString()); 
      } 
     } 
    } 

    //[DataContract] 
    public class MyXmlClassUndecorated 
    { 
     public MyElementName1[] MyElementName1 { get; set; } 

     public MyXmlClassUndecorated() 
     { 
      MyElementName1 = new MyElementName1[] { new MyElementName1("A A A A A"), new MyElementName1("A A A A A") }; 
     } 
    } 

    [DataContract] 
    public class MyXmlClassDecorated 
    { 
     public MyElementName1[] MyElementName1 { get; set; } 

     public MyXmlClassDecorated() 
     { 
      MyElementName1 = new MyElementName1[] { new MyElementName1("A A A A A"), new MyElementName1("A A A A A") }; 
     } 
    } 

    [DataContract] 
    public class MyElementName1 
    { 
     [DataMember] 
     public string Value { get; set; } 

     public MyElementName1(string value) { Value = value; } 
    } 
} 
관련 문제