Различные методы сериализации полей в поле ntext SQL при сохранении обратной совместимости

TL, DR: мы сериализовали некоторые данные в некоторых таблицах нашей базы данных SQL. К сожалению, эта методика сериализации тратит много места для символов разметки. Мы нашли новый, более эффективный способ: сохранить обратную совместимость, безопасно ли придерживаться следующей логики? -> Когда происходит сериализация, она всегда происходит с использованием нового, более эффективного способа. Когда происходит десериализация, мы проверяем, использует ли строка новый формат сериализации или старый -> затем мы десериализовываем с помощью соответствующего метода. Это надежно? Можно ли это использовать в производстве? Нет ли каких-либо тонких проблем с этим подходом?


Привет. Я работаю над приложением, которое взаимодействует с базой данных SQL. Чтобы выполнить конкретные бизнес-требования, мы сериализовали некоторые данные в специальном столбце наших таблиц БД типа ntext. По сути, в каждой ячейке этого столбца мы сериализуем массив объекта "Атрибут", поэтому typeof(T) равен Attributo []:

Определение "Атрибут" выглядит следующим образом:

public class Attributo
{
    public virtual String Nome { get; set; }
    public virtual String Valore { get; set; }
    public virtual String Tipologia { get; set; }
}

- десериализация для считывания фактических значений:

XMLUtilities.Deserialize<Attributo[]>(value));
  • Сериализация для хранения значений в столбце (для каждой строки..):

    XMLUtilities.Serialize (attributes.ToArray ());

И это вспомогательный класс, который использует объект XmlSerializer:

public static class XMLUtilities
{
    public static T Deserialize<T>(String xmlString)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));

        using (TextReader reader = new StringReader(xmlString))
        {
            return (T) serializer.Deserialize(reader);
        }
    }

    public static String Serialize<T>(T xmlObject)
    {
        MemoryStream stream = new MemoryStream();

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

        XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
        xmlnsEmpty.Add("", "");

        serializer.Serialize(stream, xmlObject, xmlnsEmpty);

        stream.Seek(0, SeekOrigin.Begin);

        using (StreamReader reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
}

Теперь проблема с этой техникой заключается в том, что она тратит много места для символов разметки. Это пример строки, которая хранится в БД:

<?xml version="1.0"?>
<ArrayOfAttributo>
  <Attributo>
    <Nome>Leakage_test_Time_prg1_p1</Nome>
    <Valore>4</Valore>
    <Tipologia>Single</Tipologia>
  </Attributo>
  <Attributo>
    <Nome>Leakage_air_Volume_p1</Nome>
    <Valore>14</Valore>
    <Tipologia>Single</Tipologia>
  </Attributo>
</ArrayOfAttributo>

Итак, мы нашли более краткий способ сериализации этих атрибутов [], который производит такой вид вывода:

<ArrayOfA xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <A>
    <N>Leakage_test_Time_prg1_p1</N>
    <V>4</V>
    <T>Single</T>
  </A>
  <A>
    <N>Leakage_air_Volume_p1</N>
    <V>14</V>
    <T>Single</T>
  </A>
</ArrayOfA>

затем, чтобы сохранить обратную совместимость, что является основной проблемой, мы реализовали следующую логику:

  • Во время сериализации:

мы всегда сериализуем новым, более лаконичным способом

  • Во время десериализации:

мы проверяем, начинается ли строка с:

<?xml version="1.0"?>

или нет. Если это так, то это старая запись, поэтому мы десериализовали ее старым способом. В противном случае мы десериализуем с использованием нового формата.

Мы добились этого, украсив "Атрибут" следующим образом:

[DataContract(Name = "A", Namespace= "")]
public class Attributo
{
    [DataMember(Name = "N")]
    public virtual String Nome { get; set; }
    [DataMember(Name = "V")]
    public virtual String Valore { get; set; }
    [DataMember(Name = "T")]
    public virtual String Tipologia { get; set; }
}

и путем внесения следующих изменений в наши методы сериализации / десериализации, которые теперь для нового метода сериализации полагаются на объект DataContractSerializer:

public static T Deserialize<T>(String xmlString)
{               
    //let's see if it's an old-style entry...
    if (xmlString.StartsWith("<?xml version=\"1.0\"?>\r\n<ArrayOfAttributo>"))
    {
        try
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));

            using (TextReader reader = new StringReader(xmlString))
            {
                return (T)serializer.Deserialize(reader);
            }
        }
        catch { }
    }

    //..then it must be a new-style one
    DataContractSerializer ser = new DataContractSerializer(typeof(T));

    using (Stream s = _streamFromString(xmlString))
    {
        return (T) ser.ReadObject(s);
    }
}

public static String Serialize<T>(T xmlObject)
{
    MemoryStream stream1 = new MemoryStream();
    DataContractSerializer ser = new DataContractSerializer(typeof(T));
    ser.WriteObject(stream1, xmlObject);
    stream1.Position = 0;
    StreamReader sr = new StreamReader(stream1);

    string xmlString = sr.ReadToEnd();

    return xmlString;    
}

private static Stream _streamFromString(string s)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(s);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

Кажется, что все работает с этим подходом, но мы хотим оценить все возможные риски, прежде чем продолжить. Это безопасно для использования в производстве?

1 ответ

Еще одна вещь, которую нужно иметь в виду при десериализации старой записи:

  1. десериализовать старый вход в старом стиле
  2. сериализовать старую запись в новом стиле
  3. сохраните новую запись в старом стиле и удалите запись в старом стиле.

Тебе хорошо идти.

Другие вопросы по тегам