.NET XmlSerializer と同じオブジェクトへの複数の参照
-
19-09-2019 - |
質問
私のリポジトリには List<Student>
, List<Course>
そして List<Enrolment>
ここで、Enrollment には Enrolment.Student と Enrolment.Course があり、これらは前の 2 つのリストの学生またはコースの 1 つを参照します。
リポジトリで XmlSerializer を使用すると、各学生のすべてのプロパティがシリアル化されるため、冗長データが出力されます。 List<Student>
そして、同じ生徒たちへのあらゆる言及に対して、 List<Enrolment>
. 。これを解決するエレガントな方法を探しています。
逆シリアル化後、逆シリアル化によって作成された重複オブジェクト インスタンスの ID 値を使用して参照を修正できますが、これはハッキングのようです。
冗長な出力を修正する 1 つの方法は、XmlIgnore Enrolment.Student および Enrolment.Course を使用して、シリアル化用にさらに 2 つのプロパティ Enrolment.StudentID と Enrolment.CourseID を作成することです。ただし、逆シリアル化中は、Enrolment.Student および Enrolment.Course の参照を設定できません (私の知る限り)。 List<Student>
そして List<Course>
は利用できません。
私が考えたもう 1 つの方法は、オブジェクト階層の下位で各リストを個別に実行し、逆シリアル化の順序を制御することです。私はこれをやりません。
別の方法は、XmlIgnore です。 List<Enrolment>
そして初期化する登録シリアル化ヘルパー クラスを作成します。 List<Enrolment>
それ自体の逆シリアル化が完了した後。これは大変な労力のようです。
他の人は、XmlSerializer を使用して同じオブジェクトへの複数の参照をどのようにシリアル化/逆シリアル化しますか?
解決
シリアライズの痛みああ: - > ...
このため、一般的な解決策は存在ではなかった、私はMSはSilverlightのフレームワークからそれを取り除か理由だと思う。
私は、.NET Frameworkの任意の自動シリアル化のメカニズムに依存していることはありません。私自身のモデルとリポジトリのために、私は通常知っているか、簡単にプログラム的性質は、単純なスカラーもの(数値/文字列/など)であるかを決定し、(いずれかのリストであるだけでなく)他のオブジェクトへのリンクであることができます。
2つのシナリオは基本的にあります:
1:我々は、オブジェクトの/転送のみフラットな情報をシリアル化します。その場合、私は、他のオブジェクトにリンクプロパティの各IDを転送します。次に、受信機は、彼らが必要とする他のすべてのオブジェクトを取得するために、後続のクエリを作ることができます。
2:私たちは、ほとんどが直接XMLに単にいくつかのCSSを使用して、いくつかのレポート機能を表示すべてのために、いくつかのレベルで可能な限り多くの情報、すなわち、より深くネストされたXMLを転送します。その場合には、実際には同じであるオブジェクトは、XMLツリーに複数回解決されることが望ましい。
は、時々私はあまりにも多く、その後のクエリの呼び出しを避けるために、最初のシナリオを少し微調整する必要があるが、通常、私は非常によく一緒に取得します。即ち私は、我々は時に解決したい、追加されたオブジェクトを指定することができ、および/またはそれがどこかに設定されています私たちのコードベースに組み込まれています。
他のヒント
のXMLシリアライザを使用して、この問題の解決策はありません。それは重複を削除するために使用するかもしれないアイデンティティの概念がありません。
あなたができる最善のは、彼らの参照とは別にオブジェクトのプールをシリアル化することです。その後、逆シリアル化後にあなたのリストを作成し直すことができます。
ところで、あなたはのXmlSerializerは、C#に固有のものではないことを知っている?
あなたが登録にインターフェイスIXmlSerializableを実装し、WriteXmlメソッドでは例えばキーのみが含まれています学生と進路XMLを生成できます。
<Student Id="5"/>
<Course Id="6"/>
とReadXmlの説明の方法であなたは、このからの参照をロードすることができます。あなたはまた、学生やコースプロパティにXmlIgnore属性を設定する必要があります。
これは解決策としてどう思われますか:
- Xmlignore各セカンダリリファレンス、すなわちentorlment.student&entorlment.course
- 代わりに、その参照の外部キーをシリアル化/脱必要にするために使用される各セカンダリリファレンスのプロパティを作成します-XML_FKのプレフィックス。EG XML_FK_STUDENT&XML_FK_COURSE
- これらの外部キープロパティを使用して参照をロードするために脱介入後に呼び出されるメソッドXML_FinalizeSeSerializationを作成します。
あなたが/のDataContractシリアライザとリファレンスのトラッキングを使用することができますする必要があります:
//deserilaize:
using(MemoryStream memStmBack = new MemoryStream()) {
var serializerForth = new DataContractSerializer(
typeof(YourType),
null,
0x7FFF /*maxItemsInObjectGraph*/ ,
false /*ignoreExtensionDataObject*/ ,
true /*preserveObjectReferences*/ ,
null /*dataContractSurrogate*/ );
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
memStmBack.Write(data, 0, data.Length);
memStmBack.Position = 0;
var lsBack = (YourType) serializerForth.ReadObject(memStmBack);
}
//serialize...
using(MemoryStream memStm = new MemoryStream()) {
var serializer = new DataContractSerializer(
typeof(YourType),
knownTypes,
0x7FFF /*maxItemsInObjectGraph*/ ,
false /*ignoreExtensionDataObject*/ ,
true /*preserveObjectReferences*/ ,
null /*dataContractSurrogate*/ );
serializer.WriteObject(memStm, yourType);
memStm.Seek(0, SeekOrigin.Begin);
using(var streamReader = new StreamReader(memStm)) {
result = streamReader.ReadToEnd();
または使用
[Serializable]
[DataContract(IsReference = true)]