TL、DR: SQL DB のいくつかのテーブルでいくつかのデータをシリアル化しています。残念ながら、このシリアライゼーション手法は、マークアップ文字のために多くのスペースを浪費します。より効率的な新しい方法を見つけました。下位互換性を維持するために、次のロジックを採用しても安全ですか? -> シリアライゼーションが発生すると、常に新しいより効率的な方法を使用して発生します。逆シリアル化が発生すると、文字列が新しいシリアル化形式を使用しているか古い形式を使用しているかを確認し、適切な方法で逆シリアル化します。これは頑丈ですか?これは本番環境で使用できますか? このアプローチには微妙な問題はありませんか?
ご挨拶。SQL データベースと対話するアプリケーションに取り組んでいます。特定のビジネス要件を達成するために、DB テーブルの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>
そこで、これらの 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"?>
か否か。その場合、これは古いエントリであるため、古い方法でデシリアライズします。それ以外の場合は、新しい形式を使用して逆シリアル化します。
「属性」を次のように装飾することで、これを実現しました。
[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;
}
すべてがこのアプローチで機能しているように見えますが、さらに先に進む前に、考えられるすべてのリスクを評価したいと考えています。これは本番環境で安全に使用できますか?