2

JSON を介して WCF Web サービスを介してデータ モデル (コード ファースト エンティティ フレームワーク) を公開しようとしています。モデルには複数の多対多の関係があり、遅延読み込みが有効になっています。私たちの Web サービスは、複数の子オブジェクトの最初のレベルのみを返すことができるはずです。次のエラーが引き続き表示されます。

「現在のスレッドがスタック オーバーフロー状態にあるため、式を評価できません。」

このエラーは、循環参照を持つデータをシリアル化するときに発生することを認識しています。

別のスレッドを読んだ後、循環参照を処理するために次の解決策を試みました。

  • WCF および DataContractSerializer: エンティティを DataContract[IsReference=true] で明示的にマークし、すべてのプロパティを [DataMember] 属性でマークします。これにより、循環参照を使用できるようになります。T4 テンプレートを使用してエンティティを生成している場合は、テンプレートを変更してこれらの属性を追加する必要があります。
  • WCF と DataContractSerializer: 暗黙的なシリアル化。関連するナビゲーション プロパティの 1 つを [IgnoreDataMember] 属性でマークして、プロパティがシリアル化されないようにします。
  • XmlSerializer: 関連するナビゲーション プロパティを [XmlIgnore] 属性でマークする
  • その他のシリアライゼーション: 関連するナビゲーション プロパティの 1 つを [NonSerialized] (Haz が最初に言及したのは +1) でマークし、一般的なシリアライゼーションまたは [ScriptIgnore] で一部の JSON 関連のシリアライゼーションをマークします。

これらの異なるアプローチはどれもうまくいきませんでした。本当に必要なのは、最初のレベルの子オブジェクトだけです。いわば子の子はいらない。次のコードを追加して、最初のレベルの子の子オブジェクトへの参照を手動で解除しました。これは機能しましたが、有効な解決策ではありません。

    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetReportTypes")]
    public List<ReportType> GetReportTypes()
    {
        List<ReportType> result = BusinessLogic.GetReportTypes(_context).ToList();
        foreach (var x in result)
        {
            foreach (var y in x.Sections)
            {
                y.ReportType = null;
            }

        };
        return result;
    }

私は、WCF を介して公開された EF で多対多の関係を持つオブジェクトのシリアル化を処理するための堅実なアプローチを探しています。私は、データ モデルに変更を加えたり、何らかの方法で Web サービスを再構成したりすることにオープンです。

完全を期すために、以下にリストされているのは、関連するすべてのコードです。

[DataContract(IsReference = true)]
[Table("ReportType", Schema = "Reporting")]
public class ReportType
{
    [Key]
    [Column("ID")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public virtual ICollection<ReportTypeSection> Sections { get; set; }
}


[Table("Section", Schema = "Reporting")]
[DataContract(IsReference = true)]
public class Section
{
    [Key]
    [Column("ID")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [DataMember]
    public int Id { get; set; }

    [DataMember]
    public virtual ICollection<ReportTypeSection> ReportTypes { get; set; }
}

[Table("ReportTypeSection", Schema = "Reporting")]
[DataContract(IsReference=true)]
public class ReportTypeSection
{
    [Column("ID")]
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [DataMember]
    public int Id { get; set; }

    [Column("ReportTypeID")]
    [Required(ErrorMessage = "Report Type Section Foreign Key Report Type ID is Required")]
    [DataMember]
    public int ReportTypeId { get; set; }

    [Column("SectionID")]
    [Required(ErrorMessage = "Report Type Section Foreign Key Section ID is Required")]
    [DataMember]
    public int SectionId { get; set; }

    [DataMember]
    public virtual ReportType ReportType { get; set; }

    [DataMember]
    public virtual Section Section { get; set; }

}

public class BusinessLogic
{
    public static IEnumerable<ReportType> GetReportTypes(IDatabaseContext context)
    {
        IEnumerable<ReportType> result = context.ReportTypes
            .Include(a => a.Sections)
            .AsEnumerable();
        return result;
    }
}

public class ReportConfigurationService : IReportConfigurationService
{
    private IEmspeedDatabaseContext _context;
    public ReportConfigurationService(IEmspeedDatabaseContext context)
    {
        _context = context;
    }

    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "GetReportTypes")]
    public List<ReportType> GetReportTypes()
    {
        List<ReportType> result = BusinessLogic.GetReportTypes(_context).ToList();
        return result;
    }
}

[ServiceContract]
public interface IReportConfigurationService
{

    [OperationContract]
    [ApplyDataContractResolver]
    List<ReportType> GetReportTypes();
}
4

2 に答える 2

2

単一レベルのみが必要な場合は、遅延読み込みをオフにし、熱心な読み込みを使用して、最初のレベルの子エンティティのみを読み込む必要があります。そのようなナビゲーション プロパティが存在する場合、これにより、子から親への後方シリアル化が引き続き発生する可能性があります。すべてのシリアル化の問題を完全に回避するには、使用するデータと単方向の関係のみをモデル化する DTO (データ転送オブジェクト) を使用する必要があります。サービス操作で DTO を入力して返す => エンティティ モデルに依存しない DTO を構築することで、シリアル化を完全に制御できます。

于 2012-09-24T22:18:14.260 に答える
0

ciclic 参照を持つプロパティに [DataMember] 属性を配置することは避けてください (この場合、積極的に読み込みを使用します)。

[DataContract]
public class Persona
{
    [DataMember]
    [Key]
    public int IdPersona { get; set; }
    [DataMember]
    public string Nombre { get; set; }
    [DataMember]
    public List<Domicilio> Domicilios { get; set; }
}

[DataContract]
public class Domicilio
{
    [DataMember]
    [Key]
    public int IdDomicilio { get; set; }
    [DataMember]

    public Persona persona { get; set; }
}
于 2013-12-18T23:37:11.353 に答える