ここに2つの解決策があります
解決策 1:
私はこれと同じ問題を抱えていたので、あなたが言及したようにクラスとDataContract
メンバーを飾りました。DataMember
ただし、ファイルを再生成するたびにやり直す必要があるため、自動生成されたコードを直接編集するのは好きではありません。これを回避するために、MetadataType
属性を使用しました。あなたの場合、次のようになります...
まず、自動生成されたエンティティをそのまま保持します。
public partial class Comment
{
public int CommentId { get; set; }
public string Content { get; set; }
public System.DateTime Posted { get; set; }
public bool Approved { get; set; }
public int AnswersTo { get; set; }
public int PostId { get; set; }
public virtual Post Post { get; set; }
}
次に、別のファイルで別の部分クラスを作成し、次のように装飾します。
[MetadataType(typeof(Metadata))]
[DataContract(IsReference = true)]
public partial class Comment
{
private class Metadata
{
[DataMember]
public int CommentId { get; set; }
[DataMember]
public string Content { get; set; }
[DataMember]
public System.DateTime Posted { get; set; }
[DataMember]
public bool Approved { get; set; }
[DataMember]
public int AnswersTo { get; set; }
[DataMember]
public int PostId { get; set; }
[DataMember]
public virtual Post Post { get; set; } // you can remove "virtual" if you wish
}
}
MetadataType
Metadata
基本的に、相棒クラスの属性を同じ名前の属性に追加しますComment
(直接ではありませんが、私たちの目的のためには、十分に近いものです... これは別の投稿のトピックです)。もちろん、Comment
エンティティが変更された場合は、それに応じてこれを更新する必要があります。
解決策 2:
変更を加えるたびに 2 番目のファイルを編集しなければならないことは、自動生成されたファイルを直接編集する場合よりもわずかに改善されるだけです。幸いなことに、メンテナンスがはるかに簡単な別のアプローチがあります。詳細はこちらで確認できますが、要約すると、OperationContract
消費Comment
している を追加の属性で装飾するだけですReferencePreservingDataContractFormat
。そのページで提供されているコードには、無限再帰を引き起こすわずかなエラーがあることに注意してください。この投稿で述べたように、修正は非常に簡単です。まったく再帰するのではなく、新しいDataContractSerializer
このアプローチの利点は、どれだけ変更Comment
しても、何も更新する必要がないことです。
コードの例として、Comment
次のように使用しているとします。
[OperationContract]
Comment FindComment(string criteria);
あなたがする必要があるのは、追加するだけです
[OperationContract]
[ReferencePreservingDataContractFormat]
Comment FindComment(string criteria);
そして、他のどこかで、次ReferencePreservingDataContractFormat
のように定義する必要があります。
//From http://blogs.msdn.com/b/sowmy/archive/2006/03/26/561188.aspx and https://stackoverflow.com/questions/4266008/endless-loop-in-a-code-sample-on-serialization
public class ReferencePreservingDataContractFormatAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
{
IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
innerBehavior.ApplyClientBehavior(description, proxy);
}
public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
IOperationBehavior innerBehavior = new ReferencePreservingDataContractSerializerOperationBehavior(description);
innerBehavior.ApplyDispatchBehavior(description, dispatch);
}
public void Validate(OperationDescription description)
{
}
}
class ReferencePreservingDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public ReferencePreservingDataContractSerializerOperationBehavior(OperationDescription operationDescription) : base(operationDescription) { }
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
0x7FFF, //maxItemsInObjectGraph
false, //ignoreExtensionDataObject
true, //preserveObjectReferences
null //dataContractSurrogate
);
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes,
0x7FFF, //maxItemsInObjectGraph
false, //ignoreExtensionDataObject
true, //preserveObjectReferences
null //dataContractSurrogate
);
}
}
以上です!
どちらの方法でも問題なく機能します。自分に合った方法を選択してください。