Различна техника за сериализиране на полето в ntext SQL поле, като същевременно се запазва обратна съвместимост

TL, DR: ние сериализираме някои данни в някои таблици на нашата SQL DB. За съжаление тази техника за сериализация губи много място за знаци за маркиране. Намерихме нов, по-ефективен начин: за да запазим обратната съвместимост, безопасно ли е да приемем следната логика? -> Когато се случи сериализация, тя винаги се извършва по новия, по-ефективен начин. Когато настъпи десериализация, проверяваме дали низът използва новия формат за сериализация или стария --> след това десериализираме с подходящия метод. Това здраво ли е? Може ли това да се използва в производството? Няма ли някакви фини проблеми с този подход?


Поздравления. Работя върху приложение, което взаимодейства с SQL база данни. За да постигнем конкретно бизнес изискване, ние сериализираме някои данни в специална колона на нашите DB таблици от тип ntext. По принцип във всяка клетка на тази колона ние сериализираме масив от обект „Attributo“, така че typeof(T) е Attributo[]:

Дефиницията на "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();
        }
    }
}

Сега, проблемът с тази техника е, че тя губи много място за знаци за маркиране. Това е примерен низ, който се съхранява в db:

<?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>

И така, открихме по-сбит начин за сериализиране на тези Attributo[], който произвежда този вид изход:

<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"?>

или не. Ако случаят е такъв, това е стар запис, така че го десериализираме по стария начин. В противен случай ние десериализираме с помощта на новия формат.

Постигнахме това, като декорирахме „Attributo“ по следния начин:

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

Изглежда, че всичко работи с този подход, но искаме да оценим всеки възможен риск, преди да продължим. Това безопасно ли е за използване в производството?


person Carlo Arnaboldi    schedule 09.03.2016    source източник


Отговори (1)


Още нещо, което трябва да имате предвид, докато десериализирате по-стария запис:

  1. десериализиране на стария запис в стар стил
  2. сериализиране на стария запис в нов стил
  3. запазете сериализирания стар запис в нов стил и изтрийте сериализирания стар запис в стар стил.

Готово си.

person Mainoon    schedule 09.03.2016