Estoy usando XmlDictionaryWriter para serializar objetos a una base de datos con el serializador de contrato de datos. Funciona de maravilla, tanto el tamaño como la velocidad son 2 veces mejores que el uso de texto/xml.XML binario .NET con diccionario pre-compartido
Sin embargo, voy a tener que lidiar con un enorme recuento de registros en mi base de datos, donde los bytes adicionales se traducen directamente en los gigabytes de tamaño de la base de datos. Es por eso que me encantaría reducir aún más el tamaño, utilizando un diccionario XML.
¿Cómo puedo hacer eso?
veo que método estático XmlDictionaryWriter.CreateBinaryWriter acepta el parámetro 2-nd de tipo IXmlDictionary. MSDN dice "XmlDictionary para usar como diccionario compartido".
En primer lugar he tratado de usar el proporcionado por el sistema aplicación:
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);
El resultado es un framework .NET ignora completamente el diccionario, y todavía inserta las cuerdas anteriores como texto plano en lugar de sólo hacer referencia a una correspondiente entrada de diccionario.
Luego he creado mi propia implementación de 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;
}
}
El resultado es - mis métodos TryLookup se llaman bien, sin embargo DataContractSerializer.WriteObject produce un documento vacío.
¿Cómo uso un diccionario pre-compartida?
¡Gracias de antemano!
P.S. No quiero meterme con XmlBinaryReaderSession/XmlBinaryWriterSession: no tengo "sesiones", en cambio tengo una base de datos de 10 GB a la que acceden muchos hilos a la vez. Lo que quiero es solo un diccionario estático predefinido.
Actualización: OK He descubierto que solo necesito llamar a "XmlDictionaryWriter.Flush". La única pregunta que queda es: ¿por qué la implementación de IXmlDictionary suministrada por el sistema no funciona como se esperaba?