c# - 如何处理循环引用 - 或者 - 中断在公开 Entity Framework 数据模型的 WCF 服务中返回的第一级子级下的引用?

标签 c# wcf entity-framework-4 ef-code-first circular-reference

我正在尝试通过 WCF Web 服务通过 JSON 公开我的数据模型(代码优先 Entity Framework )。该模型具有多个多对多关系,并启用了延迟加载。我们的 Web 服务应该能够仅返回多个子对象的第一级。我继续收到以下错误:

“无法计算表达式,因为当前线程处于堆栈溢出状态。”

我意识到这个错误是在序列化具有循环引用的数据时发生的。

阅读另一个线程后,我尝试了以下补救措施来处理循环引用:

  • WCF 和 DataContractSerializer:显式标记您的实体 DataContract[IsReference=true] 以及具有 [DataMember] 的所有属性 属性。这将允许您使用循环引用。如果你 正在使用T4模板生成实体,您必须修改它才能添加 这些属性适合您。
  • WCF 和 DataContractSerializer:隐式序列化。标记其中之一 与 [IgnoreDataMember] 属性相关的导航属性 该属性未序列化。
  • XmlSerializer:标记一个与导航相关的属性 [XmlIgnore] 属性
  • 其他序列化:将相关导航属性之一标记为 [NonSerialized](Haz +1,他是第一个提到这一点的人) 常见序列化或 [ScriptIgnore] 用于某些 JSON 相关 序列化。

这些不同的方法都没有奏效。我真正需要的是第一级的 child 对象。可以这么说,我不需要 child 的 child 。我添加了以下代码来手动中断对第一级子对象的子对象的引用,这有效但不是有效的解决方案:

    [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 中具有多对多关系的对象的序列化 -OR- 只是为了打破第一级子级以下的引用。我愿意更改数据模型或以某种方式重新配置 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();
}

最佳答案

如果您只需要单个级别,则必须关闭延迟加载并使用预先加载来仅加载第一级子实体。如果存在这样的导航属性,这仍然可能导致从子级到父级的一些向后序列化。为了完全避免所有序列化问题,您必须使用 DTO(数据传输对象),它将仅对您想要使用的数据和单向关系进行建模。您将在服务操作中填写 DTO 并将其返回 => 您将通过构建独立于实体模型的 DTO 来完全控制序列化。

关于c# - 如何处理循环引用 - 或者 - 中断在公开 Entity Framework 数据模型的 WCF 服务中返回的第一级子级下的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12573070/

相关文章:

.net - 默认证书验证程序

c# - 实现不必要的接口(interface)成员或创建新接口(interface)?

C# Linq 动态项属性

c# - 在方法/数据成员中对 WCF 添加限制

WCF 验证错误

c# - 动态构建 Expression<Func<T,bool>> 不适用于 GreaterThen

c# - POCO 和 self 跟踪实体之间的区别

database - Entity Framework 4.0 - 从现有模型升级数据库

c# - 表为空时序列不包含匹配元素错误

c# - 如何在 C# 中将日期时间对象指定为中央标准时间或其他非 UTC 时区?